Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/nss-rs/tests/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 30 kB image not shown  

Quelle  agent.rs

  Sprache: Rust
 

use std::ffi::CStr;

use nss_rs::{
    AuthenticationStatus, Client, Error, HandshakeState, Res, SecretAgentPreInfo, Server,
    TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256, TLS_GRP_EC_SECP256R1, TLS_GRP_EC_X25519,
    TLS_SIG_ECDSA_SECP256R1_SHA256, TLS_VERSION_1_3, ZeroRttCheckResult, ZeroRttChecker,
    agent::CertificateCompressor, generate_ech_keys,
};

mod handshake;
use test_fixture::{damage_ech_config, fixture_init, now};

use crate::handshake::{
    PermissiveZeroRttChecker, Resumption, ZERO_RTT_TOKEN_DATA, connect, connect_fail,
    forward_records, resumption_setup,
};

#[test]
fn make_client() {
    fixture_init();
    let _c = Client::new("server"true).expect("should create client");
}

#[test]
fn make_server() {
    fixture_init();
    let _s = Server::new(&["key"]).expect("should create server");
}

#[test]
fn basic() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    println!("client {:p}", &client);
    let mut server = Server::new(&["key"]).expect("should create server");
    println!("server {:p}", &server);

    let bytes = client.handshake(now(), &[]).expect("send CH");
    assert!(!bytes.is_empty());
    assert_eq!(*client.state(), HandshakeState::InProgress);

    let bytes = server
        .handshake(now(), &bytes[..])
        .expect("read CH, send SH");
    assert!(!bytes.is_empty());
    assert_eq!(*server.state(), HandshakeState::InProgress);

    let bytes = client.handshake(now(), &bytes[..]).expect("send CF");
    assert!(bytes.is_empty());
    assert_eq!(*client.state(), HandshakeState::AuthenticationPending);

    client.authenticated(AuthenticationStatus::Ok);
    assert_eq!(*client.state(), HandshakeState::Authenticated(0));

    // Calling handshake() again indicates that we're happy with the cert.
    let bytes = client.handshake(now(), &[]).expect("send CF");
    assert!(!bytes.is_empty());
    assert!(client.state().is_connected());

    let client_info = client.info().expect("got info");
    assert_eq!(TLS_VERSION_1_3, client_info.version());
    assert_eq!(TLS_AES_128_GCM_SHA256, client_info.cipher_suite());
    assert_eq!(
        TLS_SIG_ECDSA_SECP256R1_SHA256,
        client_info.signature_scheme()
    );

    let bytes = server.handshake(now(), &bytes[..]).expect("finish");
    assert!(bytes.is_empty());
    assert!(server.state().is_connected());

    let server_info = server.info().expect("got info");
    assert_eq!(TLS_VERSION_1_3, server_info.version());
    assert_eq!(TLS_AES_128_GCM_SHA256, server_info.cipher_suite());
    assert_eq!(
        TLS_SIG_ECDSA_SECP256R1_SHA256,
        server_info.signature_scheme()
    );
}

fn check_client_preinfo(client_preinfo: &SecretAgentPreInfo) {
    assert_eq!(client_preinfo.version(), None);
    assert_eq!(client_preinfo.cipher_suite(), None);
    assert!(!client_preinfo.early_data());
    assert_eq!(client_preinfo.early_data_cipher(), None);
    assert_eq!(client_preinfo.max_early_data(), Ok(0));
    assert_eq!(client_preinfo.alpn(), None);
}

fn check_server_preinfo(server_preinfo: &SecretAgentPreInfo) {
    assert_eq!(server_preinfo.version(), Some(TLS_VERSION_1_3));
    assert_eq!(server_preinfo.cipher_suite(), Some(TLS_AES_128_GCM_SHA256));
    assert!(!server_preinfo.early_data());
    assert_eq!(server_preinfo.early_data_cipher(), None);
    assert_eq!(server_preinfo.max_early_data(), Ok(0));
    assert_eq!(server_preinfo.alpn(), None);
}

#[test]
fn raw() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    println!("client {client:?}");
    let mut server = Server::new(&["key"]).expect("should create server");
    println!("server {server:?}");

    let client_records = client.handshake_raw(now(), None).expect("send CH");
    assert!(!client_records.is_empty());
    assert_eq!(*client.state(), HandshakeState::InProgress);

    check_client_preinfo(&client.preinfo().expect("get preinfo"));

    let server_records =
        forward_records(now(), &mut server, client_records).expect("read CH, send SH");
    assert!(!server_records.is_empty());
    assert_eq!(*server.state(), HandshakeState::InProgress);

    check_server_preinfo(&server.preinfo().expect("get preinfo"));

    let client_records = forward_records(now(), &mut client, server_records).expect("send CF");
    assert!(client_records.is_empty());
    assert_eq!(*client.state(), HandshakeState::AuthenticationPending);

    client.authenticated(AuthenticationStatus::Ok);
    assert_eq!(*client.state(), HandshakeState::Authenticated(0));

    // Calling handshake() again indicates that we're happy with the cert.
    let client_records = client.handshake_raw(now(), None).expect("send CF");
    assert!(!client_records.is_empty());
    assert!(client.state().is_connected());

    let server_records = forward_records(now(), &mut server, client_records).expect("finish");
    assert!(server_records.is_empty());
    assert!(server.state().is_connected());

    // The client should have one certificate for the server.
    let certs = client.peer_certificate().unwrap();
    assert_eq!(1, certs.into_iter().count());
    assert!(certs.stapled_ocsp_responses().unwrap().is_empty());
    assert!(certs.signed_cert_timestamp().unwrap().is_empty());

    // The server shouldn't have a client certificate.
    assert!(server.peer_certificate().is_none());
}

#[test]
fn ocsp_stapling_and_signed_cert_timestamps() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    client
        .set_option(nss_rs::Opt::SignedCertificateTimestamps, true)
        .unwrap();
    let ocsp_response = b"fake ocsp response";
    let scts = b"fake signed certificate timestamps";
    let mut server = Server::new_with_ocsp_and_scts(&["key"], &[&ocsp_response[..]], scts)
        .expect("should create server");

    connect(&mut client, &mut server);

    let certs = client.peer_certificate().unwrap();
    assert_eq!(1, certs.into_iter().count());
    let ocsp = certs.stapled_ocsp_responses().unwrap();
    assert_eq!(ocsp.len(), 1);
    assert_eq!(ocsp[0], ocsp_response);
    assert_eq!(certs.signed_cert_timestamp().unwrap(), scts);
}

#[test]
fn chacha_client() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");
    client
        .set_ciphers(&[TLS_CHACHA20_POLY1305_SHA256])
        .expect("ciphers set");

    connect(&mut client, &mut server);

    assert_eq!(
        client.info().unwrap().cipher_suite(),
        TLS_CHACHA20_POLY1305_SHA256
    );
    assert_eq!(
        server.info().unwrap().cipher_suite(),
        TLS_CHACHA20_POLY1305_SHA256
    );
}

#[test]
fn server_prefers_first_client_share() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");
    server
        .set_groups(&[TLS_GRP_EC_X25519, TLS_GRP_EC_SECP256R1])
        .expect("groups set");
    client
        .set_groups(&[TLS_GRP_EC_X25519, TLS_GRP_EC_SECP256R1])
        .expect("groups set");
    client
        .send_additional_key_shares(1)
        .expect("should set additional key share count");

    connect(&mut client, &mut server);

    assert_eq!(client.info().unwrap().key_exchange(), TLS_GRP_EC_X25519);
    assert_eq!(server.info().unwrap().key_exchange(), TLS_GRP_EC_X25519);
}

#[test]
fn server_prefers_second_client_share() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");
    server
        .set_groups(&[TLS_GRP_EC_SECP256R1, TLS_GRP_EC_X25519])
        .expect("groups set");
    client
        .set_groups(&[TLS_GRP_EC_X25519, TLS_GRP_EC_SECP256R1])
        .expect("groups set");
    client
        .send_additional_key_shares(1)
        .expect("should set additional key share count");

    connect(&mut client, &mut server);

    assert_eq!(client.info().unwrap().key_exchange(), TLS_GRP_EC_SECP256R1);
    assert_eq!(server.info().unwrap().key_exchange(), TLS_GRP_EC_SECP256R1);
}

#[test]
fn p256_server() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");
    server
        .set_groups(&[TLS_GRP_EC_SECP256R1])
        .expect("groups set");

    connect(&mut client, &mut server);

    assert_eq!(client.info().unwrap().key_exchange(), TLS_GRP_EC_SECP256R1);
    assert_eq!(server.info().unwrap().key_exchange(), TLS_GRP_EC_SECP256R1);
}

#[test]
fn p256_server_hrr() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");
    server
        .set_groups(&[TLS_GRP_EC_SECP256R1])
        .expect("groups set");
    client
        .set_groups(&[TLS_GRP_EC_X25519, TLS_GRP_EC_SECP256R1])
        .expect("groups set");
    client
        .send_additional_key_shares(0)
        .expect("should set additional key share count");

    connect(&mut client, &mut server);

    assert_eq!(client.info().unwrap().key_exchange(), TLS_GRP_EC_SECP256R1);
    assert_eq!(server.info().unwrap().key_exchange(), TLS_GRP_EC_SECP256R1);
}

#[test]
fn alpn() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    client.set_alpn(&["alpn"]).expect("should set ALPN");
    let mut server = Server::new(&["key"]).expect("should create server");
    server.set_alpn(&["alpn"]).expect("should set ALPN");

    connect(&mut client, &mut server);

    let expected = Some(String::from("alpn"));
    assert_eq!(expected.as_deref(), client.info().unwrap().alpn());
    assert_eq!(expected.as_deref(), server.info().unwrap().alpn());
}

#[test]
fn bad_alpn() {
    fixture_init();
    let mut client = Client::new("server.example"true).unwrap();
    client.set_alpn::<&[u8]>(&[]).expect_err("empty list");
    client.set_alpn(&[""]).expect_err("list with empty value");
    client
        .set_alpn(&[[0256]])
        .expect_err("list with too long value");
}

#[test]
fn alpn_multi() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    client
        .set_alpn(&["dummy""alpn"])
        .expect("should set ALPN");
    let mut server = Server::new(&["key"]).expect("should create server");
    server
        .set_alpn(&["alpn""other"])
        .expect("should set ALPN");

    connect(&mut client, &mut server);

    let expected = Some(String::from("alpn"));
    assert_eq!(expected.as_deref(), client.info().unwrap().alpn());
    assert_eq!(expected.as_deref(), server.info().unwrap().alpn());
}

#[test]
fn alpn_server_pref() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    client
        .set_alpn(&["dummy""alpn"])
        .expect("should set ALPN");
    let mut server = Server::new(&["key"]).expect("should create server");
    server
        .set_alpn(&["alpn""dummy"])
        .expect("should set ALPN");

    connect(&mut client, &mut server);

    let expected = Some(String::from("alpn"));
    assert_eq!(expected.as_deref(), client.info().unwrap().alpn());
    assert_eq!(expected.as_deref(), server.info().unwrap().alpn());
}

#[test]
fn alpn_no_protocol() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    client.set_alpn(&["a"]).expect("should set ALPN");
    let mut server = Server::new(&["key"]).expect("should create server");
    server.set_alpn(&["b"]).expect("should set ALPN");

    connect_fail(&mut client, &mut server);

    // TODO(mt) check the error code
}

#[test]
fn alpn_client_only() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    client.set_alpn(&["alpn"]).expect("should set ALPN");
    let mut server = Server::new(&["key"]).expect("should create server");

    connect(&mut client, &mut server);

    assert_eq!(None, client.info().unwrap().alpn());
    assert_eq!(None, server.info().unwrap().alpn());
}

#[test]
fn alpn_server_only() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");
    server.set_alpn(&["alpn"]).expect("should set ALPN");

    connect(&mut client, &mut server);

    assert_eq!(None, client.info().unwrap().alpn());
    assert_eq!(None, server.info().unwrap().alpn());
}

#[test]
fn resume() {
    let (_, token) = resumption_setup(Resumption::WithoutZeroRtt);

    let mut client = Client::new("server.example"true).expect("should create second client");
    let mut server = Server::new(&["key"]).expect("should create second server");

    client
        .enable_resumption(token)
        .expect("should accept token");
    connect(&mut client, &mut server);

    assert!(client.info().unwrap().resumed());
    assert!(server.info().unwrap().resumed());
}

#[test]
fn zero_rtt() {
    let (anti_replay, token) = resumption_setup(Resumption::WithZeroRtt);

    // Finally, 0-RTT should succeed.
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");
    client
        .enable_resumption(token)
        .expect("should accept token");
    client.enable_0rtt().expect("should enable 0-RTT");
    server
        .enable_0rtt(
            anti_replay.as_ref().unwrap(),
            0xffff_ffff,
            Box::<PermissiveZeroRttChecker>::default(),
        )
        .expect("should enable 0-RTT");

    connect(&mut client, &mut server);
    assert!(client.info().unwrap().early_data_accepted());
    assert!(server.info().unwrap().early_data_accepted());
}

#[test]
fn zero_rtt_no_eoed() {
    let (anti_replay, token) = resumption_setup(Resumption::WithZeroRtt);

    // Finally, 0-RTT should succeed.
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");
    client
        .enable_resumption(token)
        .expect("should accept token");
    client.enable_0rtt().expect("should enable 0-RTT");
    client
        .disable_end_of_early_data()
        .expect("should disable EOED");
    server
        .enable_0rtt(
            anti_replay.as_ref().unwrap(),
            0xffff_ffff,
            Box::<PermissiveZeroRttChecker>::default(),
        )
        .expect("should enable 0-RTT");
    server
        .disable_end_of_early_data()
        .expect("should disable EOED");

    connect(&mut client, &mut server);
    assert!(client.info().unwrap().early_data_accepted());
    assert!(server.info().unwrap().early_data_accepted());
}

#[derive(Debug)]
struct RejectZeroRtt {}
impl ZeroRttChecker for RejectZeroRtt {
    fn check(&self, token: &[u8]) -> ZeroRttCheckResult {
        assert_eq!(ZERO_RTT_TOKEN_DATA, token);
        ZeroRttCheckResult::Reject
    }
}

#[test]
fn reject_zero_rtt() {
    let (anti_replay, token) = resumption_setup(Resumption::WithZeroRtt);

    // Finally, 0-RTT should succeed.
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");
    client
        .enable_resumption(token)
        .expect("should accept token");
    client.enable_0rtt().expect("should enable 0-RTT");
    server
        .enable_0rtt(
            anti_replay.as_ref().unwrap(),
            0xffff_ffff,
            Box::new(RejectZeroRtt {}),
        )
        .expect("should enable 0-RTT");

    connect(&mut client, &mut server);
    assert!(!client.info().unwrap().early_data_accepted());
    assert!(!server.info().unwrap().early_data_accepted());
}

#[test]
fn close() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");
    connect(&mut client, &mut server);
    client.close();
    server.close();
}

#[test]
fn close_client_twice() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");
    connect(&mut client, &mut server);
    client.close();
    client.close(); // Should be a noop.
}

#[test]
fn ech() {
    fixture_init();
    let mut server = Server::new(&["key"]).expect("should create server");
    let (sk, pk) = generate_ech_keys().expect("ECH keys");
    server
        .enable_ech(88"public.example", &sk, &pk)
        .expect("should enable server ECH");

    let mut client = Client::new("server.example"true).expect("should create client");
    client
        .enable_ech(server.ech_config())
        .expect("should enable client ECH");

    connect(&mut client, &mut server);
    assert!(client.info().unwrap().ech_accepted());
    assert!(server.info().unwrap().ech_accepted());
    assert!(client.preinfo().unwrap().ech_accepted().unwrap());
    assert!(server.preinfo().unwrap().ech_accepted().unwrap());
}

#[test]
fn ech_retry() {
    const PUBLIC_NAME: &str = "public.example";
    const PRIVATE_NAME: &str = "private.example";
    const CONFIG_ID: u8 = 7;

    fixture_init();
    let mut server = Server::new(&["key"]).unwrap();
    let (sk, pk) = generate_ech_keys().unwrap();
    server.enable_ech(CONFIG_ID, PUBLIC_NAME, &sk, &pk).unwrap();

    let mut client = Client::new(PRIVATE_NAME, true).unwrap();
    client
        .enable_ech(damage_ech_config(server.ech_config()))
        .unwrap();

    // Long version of connect() so that we can check the state.
    let records = client.handshake_raw(now(), None).unwrap(); // ClientHello
    let records = forward_records(now(), &mut server, records).unwrap(); // ServerHello...
    let records = forward_records(now(), &mut client, records).unwrap(); // (empty)
    assert!(records.is_empty());

    // The client should now be expecting authentication.
    assert_eq!(
        *client.state(),
        HandshakeState::EchFallbackAuthenticationPending(String::from(PUBLIC_NAME))
    );
    client.authenticated(AuthenticationStatus::Ok);
    let Err(Error::EchRetry(updated_config)) = client.handshake_raw(now(), None) else {
        panic!(
            "Handshake should fail with EchRetry, state is instead {:?}",
            client.state()
        );
    };
    assert_eq!(
        client
            .preinfo()
            .unwrap()
            .ech_public_name()
            .unwrap()
            .unwrap(),
        PUBLIC_NAME
    );
    // We don't forward alerts, so we can't tell the server about them.
    // An ech_required alert should be set though.
    assert_eq!(client.alert(), Some(121));

    let mut server = Server::new(&["key"]).unwrap();
    server.enable_ech(CONFIG_ID, PUBLIC_NAME, &sk, &pk).unwrap();
    let mut client = Client::new(PRIVATE_NAME, true).unwrap();
    client.enable_ech(&updated_config).unwrap();

    connect(&mut client, &mut server);

    assert!(client.info().unwrap().ech_accepted());
    assert!(server.info().unwrap().ech_accepted());
    assert!(client.preinfo().unwrap().ech_accepted().unwrap());
    assert!(server.preinfo().unwrap().ech_accepted().unwrap());
}

#[test]
fn connection_succeeds_when_server_and_client_support_cert_compr_copy() {
    struct IncDecCompression {}

    // Implementation supports both encoder and decoder
    impl CertificateCompressor for IncDecCompression {
        const ID: u16 = 0x4;
        const NAME: &CStr = c"inc-dec";
        const ENABLE_ENCODING: bool = true;

        fn decode(input: &[u8], output: &mut [u8]) -> Res<()> {
            let len = std::cmp::min(input.len(), output.len());
            for i in 0..len {
                output[i] = input[i].wrapping_sub(1);
            }
            Ok(())
        }

        fn encode(input: &[u8], output: &mut [u8]) -> Res<usize> {
            let len = std::cmp::min(input.len(), output.len());
            for i in 0..len {
                output[i] = input[i].wrapping_add(1);
            }
            Ok(len)
        }
    }

    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");

    client
        .set_certificate_compression::<IncDecCompression>()
        .unwrap();
    server
        .set_certificate_compression::<IncDecCompression>()
        .unwrap();

    connect(&mut client, &mut server);

    assert!(client.state().is_connected());
    assert!(server.state().is_connected());
}

#[test]
fn connection_succeeds_when_server_and_client_default_encoding() {
    struct DefaultEncoding {}

    // Implementation supports both encoder and decoder
    impl CertificateCompressor for DefaultEncoding {
        const ID: u16 = 0x4;
        const NAME: &CStr = c"copy";
        const ENABLE_ENCODING: bool = true;

        fn decode(input: &[u8], output: &mut [u8]) -> Res<()> {
            let len = std::cmp::min(input.len(), output.len());
            output[..len].copy_from_slice(&input[..len]);
            Ok(())
        }
    }

    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");

    client
        .set_certificate_compression::<DefaultEncoding>()
        .unwrap();
    server
        .set_certificate_compression::<DefaultEncoding>()
        .unwrap();

    connect(&mut client, &mut server);

    assert!(client.state().is_connected());
    assert!(server.state().is_connected());
}

struct CopyCompressionNoEncoder {}

impl CertificateCompressor for CopyCompressionNoEncoder {
    const ID: u16 = 0x4;
    const NAME: &CStr = c"copy";

    fn decode(input: &[u8], output: &mut [u8]) -> Res<()> {
        let len = std::cmp::min(input.len(), output.len());
        output[..len].copy_from_slice(&input[..len]);
        Ok(())
    }
}

#[test]
fn connection_succeeds_when_server_and_client_support_cert_compr_copy_without_encoder() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");

    client
        .set_certificate_compression::<CopyCompressionNoEncoder>()
        .unwrap();
    server
        .set_certificate_compression::<CopyCompressionNoEncoder>()
        .unwrap();

    connect(&mut client, &mut server);

    assert!(client.state().is_connected());
    assert!(server.state().is_connected());
}

#[test]
fn connection_succeeds_when_only_server_support_cert_compr() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");

    server
        .set_certificate_compression::<CopyCompressionNoEncoder>()
        .unwrap();

    connect(&mut client, &mut server);

    assert!(client.state().is_connected());
    assert!(server.state().is_connected());
}

#[test]
fn connection_succeeds_when_only_client_support_cert_compr() {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");

    client
        .set_certificate_compression::<CopyCompressionNoEncoder>()
        .unwrap();

    connect(&mut client, &mut server);

    assert!(client.state().is_connected());
    assert!(server.state().is_connected());
}

#[test]
fn connection_fails_when_decoding_fails() {
    struct CopyCompressionDecoderReturnsErr {}

    impl CertificateCompressor for CopyCompressionDecoderReturnsErr {
        const ID: u16 = 0x4;
        const NAME: &CStr = c"copy";

        const ENABLE_ENCODING: bool = true;

        fn decode(input: &[u8], output: &mut [u8]) -> Res<()> {
            let len = std::cmp::min(input.len(), output.len());
            output[..len].copy_from_slice(&input[..len]);
            Err(Error::CertificateDecoding)
        }
    }

    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");

    server
        .set_certificate_compression::<CopyCompressionDecoderReturnsErr>()
        .unwrap();

    client
        .set_certificate_compression::<CopyCompressionDecoderReturnsErr>()
        .unwrap();

    connect_fail(&mut client, &mut server);
}

#[test]
fn connection_fails_when_encoding_fails() {
    struct CopyCompressionEncoderReturnsErr {}

    impl CertificateCompressor for CopyCompressionEncoderReturnsErr {
        const ID: u16 = 0x4;
        const NAME: &CStr = c"copy";

        const ENABLE_ENCODING: bool = true;

        fn encode(input: &[u8], output: &mut [u8]) -> Res<usize> {
            let len = std::cmp::min(input.len(), output.len());
            for i in 0..len {
                output[i] = input[i].wrapping_add(1);
            }
            Err(Error::CertificateEncoding)
        }

        fn decode(input: &[u8], output: &mut [u8]) -> Res<()> {
            let len = std::cmp::min(input.len(), output.len());
            output[..len].copy_from_slice(&input[..len]);
            Ok(())
        }
    }

    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");

    server
        .set_certificate_compression::<CopyCompressionEncoderReturnsErr>()
        .unwrap();

    client
        .set_certificate_compression::<CopyCompressionEncoderReturnsErr>()
        .unwrap();

    connect_fail(&mut client, &mut server);
}

#[test]
fn connection_fails_encoder_returned_too_long() {
    struct CompressionEncoderReturnsTooLong {}

    impl CertificateCompressor for CompressionEncoderReturnsTooLong {
        const ID: u16 = 0x4;
        const NAME: &CStr = c"copy";

        const ENABLE_ENCODING: bool = true;
        fn encode(input: &[u8], output: &mut [u8]) -> Res<usize> {
            let len = std::cmp::min(input.len(), output.len());
            for i in 0..len {
                output[i] = input[i].wrapping_sub(1);
            }
            Ok(len + 10)
        }

        fn decode(input: &[u8], output: &mut [u8]) -> Res<()> {
            let len = std::cmp::min(input.len(), output.len());
            output[..len].copy_from_slice(&input[..len]);
            Ok(())
        }
    }

    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");

    server
        .set_certificate_compression::<CompressionEncoderReturnsTooLong>()
        .unwrap();

    client
        .set_certificate_compression::<CompressionEncoderReturnsTooLong>()
        .unwrap();

    connect_fail(&mut client, &mut server);
}

fn connected_pair() -> (Client, Server) {
    fixture_init();
    let mut client = Client::new("server.example"true).expect("should create client");
    let mut server = Server::new(&["key"]).expect("should create server");
    connect(&mut client, &mut server);
    (client, server)
}

#[test]
fn export_keying_material_basic() {
    let (client, _server) = connected_pair();

    let mut material = vec![0u8; 32];
    client
        .export_keying_material(b"EXPORTER-test", &[], &mut material)
        .expect("should export keying material");
    assert_ne!(material, vec![0u8; 32]);
}

#[test]
fn export_keying_material_differs_across_connections() {
    let label = b"EXPORTER-test";
    let context = b"context-data";

    let (client1, _server1) = connected_pair();
    let mut material1 = vec![0u8; 32];
    client1
        .export_keying_material(label, context, &mut material1)
        .expect("first connection export");

    let (client2, _server2) = connected_pair();
    let mut material2 = vec![0u8; 32];
    client2
        .export_keying_material(label, context, &mut material2)
        .expect("second connection export");

    assert_ne!(
        material1, material2,
        "Different connections should produce different keying material"
    );
}

#[test]
fn export_keying_material_different_labels() {
    let (client, _server) = connected_pair();

    let mut material1 = vec![0u8; 32];
    client
        .export_keying_material(b"EXPORTER-test1", &[], &mut material1)
        .expect("export with label1");
    let mut material2 = vec![0u8; 32];
    client
        .export_keying_material(b"EXPORTER-test2", &[], &mut material2)
        .expect("export with label2");

    assert_ne!(
        material1, material2,
        "Different labels should produce different output"
    );
}

#[test]
fn export_keying_material_different_contexts() {
    let (client, _server) = connected_pair();

    let mut material1 = vec![0u8; 32];
    client
        .export_keying_material(b"EXPORTER-test", b"context1", &mut material1)
        .expect("export with context1");
    let mut material2 = vec![0u8; 32];
    client
        .export_keying_material(b"EXPORTER-test", b"context2", &mut material2)
        .expect("export with context2");

    assert_ne!(
        material1, material2,
        "Different contexts should produce different output"
    );
}

#[test]
fn export_keying_material_before_handshake() {
    fixture_init();
    let client = Client::new("server.example"true).expect("should create client");

    assert_eq!(
        client
            .export_keying_material(b"EXPORTER-test", &[], &mut [0u8; 32])
            .unwrap_err(),
        Error::InvalidState
    );
}

#[test]
fn export_keying_material_zero_length() {
    let (client, _server) = connected_pair();

    assert_eq!(
        client
            .export_keying_material(b"EXPORTER-test", &[], &mut [])
            .unwrap_err(),
        Error::InvalidInput
    );
}

#[test]
fn export_keying_material_same_for_both_sides() {
    let (client, server) = connected_pair();

    let label = b"EXPORTER-test";
    let context = b"shared-context";

    let mut client_material = vec![0u8; 32];
    client
        .export_keying_material(label, context, &mut client_material)
        .expect("client export");
    let mut server_material = vec![0u8; 32];
    server
        .export_keying_material(label, context, &mut server_material)
        .expect("server export");

    assert_eq!(
        client_material, server_material,
        "Both sides should export identical material"
    );
}

Messung V0.5 in Prozent
C=98 H=98 G=97

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.