File: unbuffered.rs

package info (click to toggle)
rust-rustls 0.23.26%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 13,816 kB
  • sloc: sh: 199; python: 181; makefile: 23
file content (85 lines) | stat: -rw-r--r-- 2,894 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#![no_main]
#[macro_use]
extern crate libfuzzer_sys;
extern crate rustls;

use rustls::client::UnbufferedClientConnection;
use rustls::server::UnbufferedServerConnection;
use rustls::unbuffered::{ConnectionState, UnbufferedStatus};
use rustls::{ClientConfig, ServerConfig, SideData};

fuzz_target!(|data: &[u8]| {
    let _ = env_logger::try_init();
    let mut data = data.to_vec();
    match data.split_first_mut() {
        Some((0x00, rest)) => client(rest),
        Some((0x01, rest)) => server(rest),
        Some((_, _)) | None => {}
    }
});

fn client(data: &mut [u8]) {
    let config = ClientConfig::builder_with_provider(rustls_fuzzing_provider::provider().into())
        .with_safe_default_protocol_versions()
        .unwrap()
        .dangerous()
        .with_custom_certificate_verifier(rustls_fuzzing_provider::server_verifier())
        .with_no_client_auth();
    let conn =
        UnbufferedClientConnection::new(config.into(), "localhost".try_into().unwrap()).unwrap();
    fuzz_unbuffered(data, ClientServer::Client(conn));
}

fn server(data: &mut [u8]) {
    let config = ServerConfig::builder_with_provider(rustls_fuzzing_provider::provider().into())
        .with_safe_default_protocol_versions()
        .unwrap()
        .with_no_client_auth()
        .with_cert_resolver(rustls_fuzzing_provider::server_cert_resolver());
    let conn = UnbufferedServerConnection::new(config.into()).unwrap();
    fuzz_unbuffered(data, ClientServer::Server(conn));
}

enum ClientServer {
    Client(UnbufferedClientConnection),
    Server(UnbufferedServerConnection),
}

fn fuzz_unbuffered(mut data: &mut [u8], mut conn: ClientServer) {
    while !data.is_empty() {
        let consumed = match &mut conn {
            ClientServer::Server(server) => process(server.process_tls_records(data)),
            ClientServer::Client(client) => process(client.process_tls_records(data)),
        };

        match consumed {
            Some(consumed) => {
                data = &mut data[consumed..];
            }
            None => break,
        };
    }
}

fn process<S: SideData>(status: UnbufferedStatus<'_, '_, S>) -> Option<usize> {
    let UnbufferedStatus { discard, state } = status;

    match state {
        Ok(ConnectionState::EncodeTlsData(mut enc)) => {
            let mut buffer = [0u8; 16_384 + 5]; // big enough for largest TLS packet
            enc.encode(&mut buffer).unwrap();
        }
        Ok(ConnectionState::TransmitTlsData(xmit)) => xmit.done(),
        Ok(ConnectionState::WriteTraffic(_)) => return None,
        Ok(ConnectionState::BlockedHandshake) => return None,
        Ok(ConnectionState::ReadTraffic(mut read)) => loop {
            let Some(_app_data) = read.next_record() else {
                break;
            };
        },
        Ok(st) => panic!("unhandled state {st:?}"),
        Err(_) => return None,
    };

    Some(discard)
}