diff --git a/.cargo/config.toml.in b/.cargo/config.toml.in index 4f5e840691a3..156a12bfcfd1 100644 --- a/.cargo/config.toml.in +++ b/.cargo/config.toml.in @@ -100,9 +100,9 @@ git = "https://github.com/mozilla/mp4parse-rust" rev = "e64650a686e5c5732395cd059e17cfd3b1e5b63b" replace-with = "vendored-sources" -[source."git+https://github.com/mozilla/neqo?tag=v0.12.2"] +[source."git+https://github.com/mozilla/neqo?tag=v0.13.1"] git = "https://github.com/mozilla/neqo" -tag = "v0.12.2" +tag = "v0.13.1" replace-with = "vendored-sources" [source."git+https://github.com/servo/rust-cssparser?rev=958a3f098acb92ddacdce18a7ef2c4a87ac3326f"] diff --git a/Cargo.lock b/Cargo.lock index caee9fbd26ba..06814fa3e844 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4522,8 +4522,8 @@ dependencies = [ [[package]] name = "neqo-bin" -version = "0.12.2" -source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" +version = "0.13.1" +source = "git+https://github.com/mozilla/neqo?tag=v0.13.1#0a356afeb45631036df6b3028951a02d16fa8d27" dependencies = [ "clap", "clap-verbosity-flag", @@ -4544,35 +4544,38 @@ dependencies = [ [[package]] name = "neqo-common" -version = "0.12.2" -source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" +version = "0.13.1" +source = "git+https://github.com/mozilla/neqo?tag=v0.13.1#0a356afeb45631036df6b3028951a02d16fa8d27" dependencies = [ "enum-map", "env_logger", "log", "qlog", + "strum", "windows", ] [[package]] name = "neqo-crypto" -version = "0.12.2" -source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" +version = "0.13.1" +source = "git+https://github.com/mozilla/neqo?tag=v0.13.1#0a356afeb45631036df6b3028951a02d16fa8d27" dependencies = [ "bindgen 0.69.4", + "enum-map", "log", "mozbuild", "neqo-common", "semver", "serde", "serde_derive", + "strum", "toml", ] [[package]] name = "neqo-http3" -version = "0.12.2" -source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" +version = "0.13.1" +source = "git+https://github.com/mozilla/neqo?tag=v0.13.1#0a356afeb45631036df6b3028951a02d16fa8d27" dependencies = [ "enumset", "log", @@ -4582,13 +4585,14 @@ dependencies = [ "neqo-transport", "qlog", "sfv", + "strum", "url", ] [[package]] name = "neqo-qpack" -version = "0.12.2" -source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" +version = "0.13.1" +source = "git+https://github.com/mozilla/neqo?tag=v0.13.1#0a356afeb45631036df6b3028951a02d16fa8d27" dependencies = [ "log", "neqo-common", @@ -4599,10 +4603,11 @@ dependencies = [ [[package]] name = "neqo-transport" -version = "0.12.2" -source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" +version = "0.13.1" +source = "git+https://github.com/mozilla/neqo?tag=v0.13.1#0a356afeb45631036df6b3028951a02d16fa8d27" dependencies = [ "enum-map", + "enumset", "indexmap", "log", "mtu", @@ -4611,12 +4616,13 @@ dependencies = [ "qlog", "smallvec", "static_assertions", + "strum", ] [[package]] name = "neqo-udp" -version = "0.12.2" -source = "git+https://github.com/mozilla/neqo?tag=v0.12.2#f8946d5187271b3e63e8d0209343510bdeac1451" +version = "0.13.1" +source = "git+https://github.com/mozilla/neqo?tag=v0.13.1#0a356afeb45631036df6b3028951a02d16fa8d27" dependencies = [ "cfg_aliases", "log", @@ -5284,12 +5290,11 @@ dependencies = [ [[package]] name = "qlog" -version = "0.13.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b5f65b920fa913ce92267bb3c4ed3b9c2f81d05f8e1376c3bbc95455eedb7df" +checksum = "0f15b83c59e6b945f2261c95a1dd9faf239187f32ff0a96af1d1d28c4557f919" dependencies = [ "serde", - "serde_derive", "serde_json", "serde_with", "smallvec", @@ -5303,9 +5308,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quinn-udp" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" +checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5" dependencies = [ "cfg_aliases", "libc", diff --git a/netwerk/socket/neqo_glue/Cargo.toml b/netwerk/socket/neqo_glue/Cargo.toml index c2288a70bf00..58ced08d55e7 100644 --- a/netwerk/socket/neqo_glue/Cargo.toml +++ b/netwerk/socket/neqo_glue/Cargo.toml @@ -10,17 +10,17 @@ name = "neqo_glue" [dependencies] firefox-on-glean = { path = "../../../toolkit/components/glean/api" } -neqo-udp = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } -neqo-http3 = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } -neqo-transport = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo", features = ["gecko"] } -neqo-common = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } -neqo-qpack = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } +neqo-udp = { tag = "v0.13.1", git = "https://github.com/mozilla/neqo" } +neqo-http3 = { tag = "v0.13.1", git = "https://github.com/mozilla/neqo" } +neqo-transport = { tag = "v0.13.1", git = "https://github.com/mozilla/neqo", features = ["gecko"] } +neqo-common = { tag = "v0.13.1", git = "https://github.com/mozilla/neqo" } +neqo-qpack = { tag = "v0.13.1", git = "https://github.com/mozilla/neqo" } nserror = { path = "../../../xpcom/rust/nserror" } nsstring = { path = "../../../xpcom/rust/nsstring" } xpcom = { path = "../../../xpcom/rust/xpcom" } thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } log = "0.4.0" -qlog = "0.13" +qlog = "0.15.1" libc = "0.2.0" static_assertions = "1.1" static_prefs = { path = "../../../modules/libpref/init/static_prefs"} @@ -30,7 +30,7 @@ uuid = { version = "1.0", features = ["v4"] } winapi = {version = "0.3", features = ["ws2def"] } [dependencies.neqo-crypto] -tag = "v0.12.2" +tag = "v0.13.1" git = "https://github.com/mozilla/neqo" default-features = false features = ["gecko"] diff --git a/netwerk/socket/neqo_glue/src/lib.rs b/netwerk/socket/neqo_glue/src/lib.rs index c99a1492b723..5d9325fb0f86 100644 --- a/netwerk/socket/neqo_glue/src/lib.rs +++ b/netwerk/socket/neqo_glue/src/lib.rs @@ -261,7 +261,10 @@ impl NeqoHttp3Conn { .max_stream_data(StreamType::BiDi, false, max_stream_data) .grease(static_prefs::pref!("security.tls.grease_http3_enable")) .sni_slicing(static_prefs::pref!("network.http.http3.sni-slicing")) - .idle_timeout(Duration::from_secs(idle_timeout.into())); + .idle_timeout(Duration::from_secs(idle_timeout.into())) + // Disabled on OpenBSD. See . + .pmtud_iface_mtu(cfg!(not(target_os = "openbsd"))) + .mlkem(false); // Set a short timeout when fuzzing. #[cfg(feature = "fuzzing")] @@ -417,10 +420,10 @@ impl NeqoHttp3Conn { } if static_prefs::pref!("network.http.http3.ecn") && stats.frame_rx.handshake_done != 0 { - if stats.ecn_tx[IpTosEcn::Ect0] > 0 { - if let Ok(ratio) = i64::try_from( - (stats.ecn_tx[IpTosEcn::Ce] * PRECISION_FACTOR) / stats.ecn_tx[IpTosEcn::Ect0], - ) { + let tx_ect0_sum: u64 = stats.ecn_tx.into_values().map(|v| v[IpTosEcn::Ect0]).sum(); + let tx_ce_sum: u64 = stats.ecn_tx.into_values().map(|v| v[IpTosEcn::Ce]).sum(); + if tx_ect0_sum > 0 { + if let Ok(ratio) = i64::try_from((tx_ce_sum * PRECISION_FACTOR) / tx_ect0_sum) { glean::http_3_ecn_ce_ect0_ratio_sent.accumulate_single_sample_signed(ratio); } else { let msg = "Failed to convert ratio to i64 for use with glean"; @@ -428,10 +431,10 @@ impl NeqoHttp3Conn { debug_assert!(false, "{msg}"); } } - if stats.ecn_rx[IpTosEcn::Ect0] > 0 { - if let Ok(ratio) = i64::try_from( - (stats.ecn_rx[IpTosEcn::Ce] * PRECISION_FACTOR) / stats.ecn_rx[IpTosEcn::Ect0], - ) { + let rx_ect0_sum: u64 = stats.ecn_rx.into_values().map(|v| v[IpTosEcn::Ect0]).sum(); + let rx_ce_sum: u64 = stats.ecn_rx.into_values().map(|v| v[IpTosEcn::Ce]).sum(); + if rx_ect0_sum > 0 { + if let Ok(ratio) = i64::try_from((rx_ce_sum * PRECISION_FACTOR) / rx_ect0_sum) { glean::http_3_ecn_ce_ect0_ratio_received.accumulate_single_sample_signed(ratio); } else { let msg = "Failed to convert ratio to i64 for use with glean"; @@ -1159,7 +1162,6 @@ impl From for CloseError { TransportError::ConnectionIdLimitExceeded => Self::TransportInternalErrorOther(1), TransportError::ConnectionIdsExhausted => Self::TransportInternalErrorOther(2), TransportError::ConnectionState => Self::TransportInternalErrorOther(3), - TransportError::DecodingFrame => Self::TransportInternalErrorOther(4), TransportError::DecryptError => Self::TransportInternalErrorOther(5), TransportError::IntegerOverflow => Self::TransportInternalErrorOther(7), TransportError::InvalidInput => Self::TransportInternalErrorOther(8), @@ -1184,6 +1186,7 @@ impl From for CloseError { TransportError::QlogError => Self::TransportInternalErrorOther(27), TransportError::NotAvailable => Self::TransportInternalErrorOther(28), TransportError::DisabledVersion => Self::TransportInternalErrorOther(29), + TransportError::UnknownTransportParameter => Self::TransportInternalErrorOther(30), } } } @@ -1213,7 +1216,6 @@ const fn transport_error_to_glean_label(error: &TransportError) -> &'static str TransportError::ConnectionIdLimitExceeded => "ConnectionIdLimitExceeded", TransportError::ConnectionIdsExhausted => "ConnectionIdsExhausted", TransportError::ConnectionState => "ConnectionState", - TransportError::DecodingFrame => "DecodingFrame", TransportError::DecryptError => "DecryptError", TransportError::DisabledVersion => "DisabledVersion", TransportError::IdleTimeout => "IdleTimeout", @@ -1242,6 +1244,7 @@ const fn transport_error_to_glean_label(error: &TransportError) -> &'static str TransportError::UnknownFrameType => "UnknownFrameType", TransportError::VersionNegotiation => "VersionNegotiation", TransportError::WrongRole => "WrongRole", + TransportError::UnknownTransportParameter => "UnknownTransportParameter", } } diff --git a/netwerk/test/http3server/Cargo.toml b/netwerk/test/http3server/Cargo.toml index 4bf3ad76d6b1..6ec0b6a15c98 100644 --- a/netwerk/test/http3server/Cargo.toml +++ b/netwerk/test/http3server/Cargo.toml @@ -6,11 +6,11 @@ edition = "2021" license = "MPL-2.0" [dependencies] -neqo-bin = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } -neqo-transport = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo", features = ["gecko"] } -neqo-common = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } -neqo-http3 = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } -neqo-qpack = { tag = "v0.12.2", git = "https://github.com/mozilla/neqo" } +neqo-bin = { tag = "v0.13.1", git = "https://github.com/mozilla/neqo" } +neqo-transport = { tag = "v0.13.1", git = "https://github.com/mozilla/neqo", features = ["gecko"] } +neqo-common = { tag = "v0.13.1", git = "https://github.com/mozilla/neqo" } +neqo-http3 = { tag = "v0.13.1", git = "https://github.com/mozilla/neqo" } +neqo-qpack = { tag = "v0.13.1", git = "https://github.com/mozilla/neqo" } log = "0.4.0" base64 = "0.22" cfg-if = "1.0" @@ -20,7 +20,7 @@ tokio = { version = "1", features = ["rt-multi-thread"] } mozilla-central-workspace-hack = { version = "0.1", features = ["http3server"], optional = true } [dependencies.neqo-crypto] -tag = "v0.12.2" +tag = "v0.13.1" git = "https://github.com/mozilla/neqo" default-features = false features = ["gecko"] diff --git a/netwerk/test/http3server/src/main.rs b/netwerk/test/http3server/src/main.rs index 640dcb83d840..75ad8ed76538 100644 --- a/netwerk/test/http3server/src/main.rs +++ b/netwerk/test/http3server/src/main.rs @@ -170,7 +170,7 @@ impl Http3TestServer { } impl HttpServer for Http3TestServer { - fn process(&mut self, dgram: Option>, now: Instant) -> Output { + fn process(&mut self, dgram: Option>, now: Instant) -> Output { let output = self.server.process(dgram, now); let output = if self.sessions_to_close.is_empty() { @@ -662,7 +662,7 @@ impl ::std::fmt::Display for Server { } impl HttpServer for Server { - fn process(&mut self, dgram: Option>, now: Instant) -> Output { + fn process(&mut self, dgram: Option>, now: Instant) -> Output { self.0.process(dgram, now) } @@ -898,7 +898,7 @@ impl Http3ProxyServer { } impl HttpServer for Http3ProxyServer { - fn process(&mut self, dgram: Option>, now: Instant) -> Output { + fn process(&mut self, dgram: Option>, now: Instant) -> Output { let output = self.server.process(dgram, now); #[cfg(not(target_os = "android"))] @@ -1027,7 +1027,7 @@ impl ::std::fmt::Display for NonRespondingServer { } impl HttpServer for NonRespondingServer { - fn process(&mut self, _dgram: Option>, _now: Instant) -> Output { + fn process(&mut self, _dgram: Option>, _now: Instant) -> Output { Output::None } diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 9a1095217460..6f007ea441d2 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -4278,6 +4278,11 @@ who = "Kershaw Chang " criteria = "safe-to-deploy" delta = "0.12.0 -> 0.13.0" +[[audits.qlog]] +who = "Max Leonard Inden " +criteria = "safe-to-deploy" +delta = "0.13.0 -> 0.15.2" + [[audits.quinn-udp]] who = "Kershaw Chang " criteria = "safe-to-run" @@ -4309,6 +4314,11 @@ who = "Max Leonard Inden " criteria = "safe-to-deploy" delta = "0.5.9 -> 0.5.10" +[[audits.quinn-udp]] +who = "Max Leonard Inden " +criteria = "safe-to-deploy" +delta = "0.5.10 -> 0.5.11" + [[audits.quote]] who = "Nika Layzell " criteria = "safe-to-deploy" diff --git a/third_party/rust/neqo-bin/.cargo-checksum.json b/third_party/rust/neqo-bin/.cargo-checksum.json index 11f261eb8258..8f638e6f3881 100644 --- a/third_party/rust/neqo-bin/.cargo-checksum.json +++ b/third_party/rust/neqo-bin/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"699f5a52f9533f1d44ad6c43324ec957d7ede0299657690146b8854536ce41e7","benches/main.rs":"fcfd00665a1c4eb2118c74dd3e066e451bed655a42ae5c92daee38a31b69c2fb","src/bin/client.rs":"d7dc368d9b3a3a7a391fd982509ce66afa09ede9ca54dc1328bfc222e69379dc","src/bin/server.rs":"f297d7d00613291e5a058772c7e416b55ad8a25e6f0cf438c7b7f836fb470135","src/client/http09.rs":"86726bac98edbcab5a41ee5e4614637944730032fb31354cb68df917992da9bd","src/client/http3.rs":"820d359d83c6d6df1ce463cf2780b4541d0bd880338b8bf7840b6f01f14732ec","src/client/mod.rs":"3a8d426736c892a69acf543ab469540b631a43ab7c18e8f4e1f74aa0f56806e2","src/lib.rs":"68936ae531d5ab903b0063e3c8a7cd49511c2bf87c42706f23e8968e8a5c3d89","src/send_data.rs":"7537b7a0f67e9077cf121cc3d0fcd42edb085801dd4baf25b14c22a01f1bf04f","src/server/http09.rs":"d71cd79bba792799f303abdc15abe10e843bc0dd4de3efa27f3d11bf82798de2","src/server/http3.rs":"56f45922eebcfa30d7d9ceb6bac97d6f725d4c803c7aa0836c6e4d21b8d4588e","src/server/mod.rs":"6286666e692c43e52ddb3e837c9630694a446101c0c8cff520a816ce25c247df","src/udp.rs":"9fbd463a87c7a1f0873a003c36631b3b02af6e1a3d215b5a12a1e2822c207362"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"632822ea728db24db8ccbba6a7b38431bba66b1c7f090e50c9bc254f16c7fa16","benches/main.rs":"7bd395227024b062e87eff0e7e2afa4a2dc70d7497c999aa665709577818f466","src/bin/client.rs":"71952208bcee80e8ff37a5dfe7cac19940274157e8ecf8acc6edc4d918c813b7","src/bin/server.rs":"88d3b2310f4a899053603cce4fd03703f26a8b91ff487bf5942b6e45c135a9fa","src/client/http09.rs":"b0b3ff496dbf35fe582a3f02780792bba34cb510d2acbcb43023180bec27cae1","src/client/http3.rs":"3f7bd425fa3bbdea005c91be6f25c861dc20819c2aeee42d4ffab7a7e3ef7282","src/client/mod.rs":"9185f1039d1e920a720330ec8b63f8b42d3924c26e95b6636436c9c5e1ae20a1","src/lib.rs":"ced2561bbebce6440b8ee902316afe7ca9df8dfeb632053587854838815e7c74","src/send_data.rs":"7537b7a0f67e9077cf121cc3d0fcd42edb085801dd4baf25b14c22a01f1bf04f","src/server/http09.rs":"b5236d9cc7b3c6c46cef9be521bc85e1b618960c0315465760a3d58e92c82c32","src/server/http3.rs":"2c826fb81a792221878a6d16bcaf6f1bed88fe0b424315c262eb08479ac5b4c4","src/server/mod.rs":"1c4c453452e5788ea3b3ab0c2d2193a291a39426466a28d8a0b384206392d485","src/udp.rs":"d68cd0fba6a0e679f79cce5c443bceba48c6ddbd2b5f492a075c9da8765b3047"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-bin/Cargo.toml b/third_party/rust/neqo-bin/Cargo.toml index 469f5943ff09..b1c62f80dfc5 100644 --- a/third_party/rust/neqo-bin/Cargo.toml +++ b/third_party/rust/neqo-bin/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.76.0" +rust-version = "1.82.0" name = "neqo-bin" -version = "0.12.2" +version = "0.13.1" authors = ["The Neqo Authors "] build = false autolib = false @@ -72,7 +72,7 @@ harness = false required-features = ["bench"] [dependencies.clap] -version = "4.4" +version = "4.5" features = [ "std", "help", @@ -118,11 +118,11 @@ path = "./../neqo-transport" path = "./../neqo-udp" [dependencies.qlog] -version = "0.13" +version = "0.15.1" default-features = false [dependencies.quinn-udp] -version = "0.5.6" +version = "0.5.11" features = [ "direct-log", "fast-apple-datapath", @@ -141,12 +141,11 @@ features = [ "time", "macros", "rt", - "rt-multi-thread", ] default-features = false [dependencies.url] -version = "2.5.3" +version = "2.5" features = ["std"] default-features = false @@ -173,22 +172,56 @@ features = ["sync"] default-features = false [lints.clippy] +allow_attributes = "warn" +allow_attributes_without_reason = "warn" cfg_not_test = "warn" clone_on_ref_ptr = "warn" create_dir = "warn" +dbg_macro = "warn" +empty_drop = "warn" +empty_enum_variants_with_brackets = "warn" +filetype_is_file = "warn" +float_cmp_const = "warn" +fn_to_numeric_cast_any = "warn" get_unwrap = "warn" if_then_some_else_none = "warn" +infinite_loop = "warn" +large_include_file = "warn" +let_underscore_must_use = "warn" +let_underscore_untyped = "warn" +literal_string_with_formatting_args = "allow" +lossy_float_literal = "warn" +mem_forget = "warn" +mixed_read_write_in_expression = "warn" +module_name_repetitions = "warn" multiple_crate_versions = "allow" multiple_inherent_impl = "warn" +mutex_atomic = "warn" +mutex_integer = "warn" +needless_raw_strings = "warn" pathbuf_init_then_push = "warn" +pub_without_shorthand = "warn" +rc_buffer = "warn" +rc_mutex = "warn" redundant_type_annotations = "warn" ref_patterns = "warn" renamed_function_params = "warn" +rest_pat_in_fully_bound_structs = "warn" +self_named_module_files = "warn" semicolon_inside_block = "warn" +string_lit_chars_any = "warn" +string_to_string = "warn" +suspicious_xor_used_as_pow = "warn" try_err = "warn" +unnecessary_safety_comment = "warn" +unnecessary_safety_doc = "warn" +unnecessary_self_imports = "warn" unneeded_field_pattern = "warn" unused_result_ok = "warn" unused_trait_names = "warn" +unwrap_in_result = "warn" +unwrap_used = "warn" +verbose_file_reads = "warn" [lints.clippy.cargo] level = "warn" @@ -205,7 +238,6 @@ priority = -1 [lints.rust] absolute_paths_not_starting_with_crate = "warn" ambiguous_negative_literals = "warn" -closure_returning_async_block = "warn" explicit_outlives_requirements = "warn" macro_use_extern_crate = "warn" missing_abi = "warn" @@ -217,3 +249,4 @@ unit_bindings = "warn" unused_import_braces = "warn" unused_lifetimes = "warn" unused_macro_rules = "warn" +unused_qualifications = "warn" diff --git a/third_party/rust/neqo-bin/benches/main.rs b/third_party/rust/neqo-bin/benches/main.rs index b2ef09873992..9f2b8530911f 100644 --- a/third_party/rust/neqo-bin/benches/main.rs +++ b/third_party/rust/neqo-bin/benches/main.rs @@ -4,11 +4,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect(clippy::unwrap_used, reason = "OK in a bench.")] + use std::{env, path::PathBuf, str::FromStr as _}; use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput}; use neqo_bin::{client, server}; -use tokio::runtime::Runtime; +use tokio::runtime::Builder; struct Benchmark { name: String, @@ -42,7 +44,7 @@ fn transfer(c: &mut Criterion) { upload: false, }, Benchmark { - name: format!("1-conn/1-100mb-resp{mtu} (aka. Upload)"), + name: format!("1-conn/1-100mb-req{mtu} (aka. Upload)"), requests: vec![100 * 1024 * 1024], upload: true, }, @@ -55,13 +57,14 @@ fn transfer(c: &mut Criterion) { Throughput::Elements(requests.len() as u64) }); group.bench_function("client", |b| { - b.to_async(Runtime::new().unwrap()).iter_batched( - || client::client(client::Args::new(&requests, upload)), - |client| async move { - client.await.unwrap(); - }, - BatchSize::PerIteration, - ); + b.to_async(Builder::new_current_thread().enable_all().build().unwrap()) + .iter_batched( + || client::client(client::Args::new(&requests, upload)), + |client| async move { + client.await.unwrap(); + }, + BatchSize::PerIteration, + ); }); group.finish(); } @@ -69,17 +72,25 @@ fn transfer(c: &mut Criterion) { done_sender.send(()).unwrap(); } -#[allow(clippy::redundant_pub_crate)] // Bug in clippy nursery? Not sure how this lint could fire here. +#[allow( + clippy::allow_attributes, + clippy::redundant_pub_crate, + reason = "TODO: Bug in clippy nursery?" +)] fn spawn_server() -> tokio::sync::oneshot::Sender<()> { let (done_sender, mut done_receiver) = tokio::sync::oneshot::channel(); std::thread::spawn(move || { - Runtime::new().unwrap().block_on(async { - let mut server = Box::pin(server::server(server::Args::default())); - tokio::select! { - _ = &mut done_receiver => {} - res = &mut server => panic!("expect server not to terminate: {res:?}"), - }; - }); + Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { + let mut server = Box::pin(server::server(server::Args::default())); + tokio::select! { + _ = &mut done_receiver => {} + res = &mut server => panic!("expect server not to terminate: {res:?}"), + }; + }); }); done_sender } diff --git a/third_party/rust/neqo-bin/src/bin/client.rs b/third_party/rust/neqo-bin/src/bin/client.rs index 51ecab6a7713..187fb8764973 100644 --- a/third_party/rust/neqo-bin/src/bin/client.rs +++ b/third_party/rust/neqo-bin/src/bin/client.rs @@ -6,7 +6,7 @@ use clap::Parser as _; -#[tokio::main] +#[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), neqo_bin::client::Error> { let args = neqo_bin::client::Args::parse(); diff --git a/third_party/rust/neqo-bin/src/bin/server.rs b/third_party/rust/neqo-bin/src/bin/server.rs index 022a950f2f7a..a0d41215c4e4 100644 --- a/third_party/rust/neqo-bin/src/bin/server.rs +++ b/third_party/rust/neqo-bin/src/bin/server.rs @@ -6,7 +6,7 @@ use clap::Parser as _; -#[tokio::main] +#[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), neqo_bin::server::Error> { let args = neqo_bin::server::Args::parse(); diff --git a/third_party/rust/neqo-bin/src/client/http09.rs b/third_party/rust/neqo-bin/src/client/http09.rs index 21b0cf2883ba..0fc600765be5 100644 --- a/third_party/rust/neqo-bin/src/client/http09.rs +++ b/third_party/rust/neqo-bin/src/client/http09.rs @@ -4,6 +4,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect(clippy::unwrap_used, reason = "This is example code.")] + //! An [HTTP 0.9](https://www.w3.org/Protocols/HTTP/AsImplemented.html) client implementation. use std::{ @@ -159,7 +161,11 @@ pub fn create_client( client.set_ciphers(&ciphers)?; } - client.set_qlog(qlog_new(args, hostname, client.odcid().unwrap())?); + client.set_qlog(qlog_new( + args, + hostname, + client.odcid().ok_or(Error::InternalError)?, + )?); Ok(client) } @@ -189,7 +195,7 @@ impl super::Client for Connection { fn process_multiple_input<'a>( &mut self, - dgrams: impl IntoIterator>, + dgrams: impl IntoIterator>, now: Instant, ) { self.process_multiple_input(dgrams, now); @@ -302,7 +308,7 @@ impl<'b> Handler<'b> { } else { qdebug!( "READ[{stream_id}]: {}", - std::str::from_utf8(read_buffer).unwrap() + std::str::from_utf8(read_buffer).map_err(|_| Error::InvalidInput)? ); } if fin { diff --git a/third_party/rust/neqo-bin/src/client/http3.rs b/third_party/rust/neqo-bin/src/client/http3.rs index ac4b22dba152..6e8e25c4d5a8 100644 --- a/third_party/rust/neqo-bin/src/client/http3.rs +++ b/third_party/rust/neqo-bin/src/client/http3.rs @@ -4,6 +4,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect(clippy::unwrap_used, reason = "This is example code.")] + //! An HTTP 3 client implementation. use std::{ @@ -18,7 +20,7 @@ use std::{ time::Instant, }; -use neqo_common::{event::Provider, hex, qdebug, qinfo, qwarn, Datagram, Header}; +use neqo_common::{event::Provider, hex, qdebug, qerror, qinfo, qwarn, Datagram, Header}; use neqo_crypto::{AuthenticationStatus, ResumptionToken}; use neqo_http3::{Error, Http3Client, Http3ClientEvent, Http3Parameters, Http3State, Priority}; use neqo_transport::{ @@ -31,7 +33,7 @@ use super::{get_output_file, qlog_new, Args, CloseState, Res}; use crate::{send_data::SendData, STREAM_IO_BUFFER_SIZE}; pub struct Handler<'a> { - #[allow(clippy::struct_field_names)] + #[expect(clippy::struct_field_names, reason = "This name is more descriptive.")] url_handler: UrlHandler<'a>, token: Option, output_read_data: bool, @@ -137,7 +139,7 @@ impl super::Client for Http3Client { fn process_multiple_input<'a>( &mut self, - dgrams: impl IntoIterator>, + dgrams: impl IntoIterator>, now: Instant, ) { self.process_multiple_input(dgrams, now); @@ -200,9 +202,11 @@ impl super::Handler for Handler<'_> { qwarn!("Data on unexpected stream: {stream_id}"); } Some(handler) => loop { - let (sz, fin) = client - .read_data(Instant::now(), stream_id, &mut self.read_buffer) - .expect("Read should succeed"); + let (sz, fin) = client.read_data( + Instant::now(), + stream_id, + &mut self.read_buffer, + )?; handler.process_data_readable( stream_id, @@ -270,7 +274,7 @@ trait StreamHandler { fin: bool, data: &[u8], output_read_data: bool, - ) -> Res; + ) -> Res<()>; fn process_data_writable(&mut self, client: &mut Http3Client, stream_id: StreamId); } @@ -291,12 +295,12 @@ impl StreamHandler for DownloadStreamHandler { fin: bool, data: &[u8], output_read_data: bool, - ) -> Res { + ) -> Res<()> { if let Some(out_file) = &mut self.out_file { if !data.is_empty() { out_file.write_all(data)?; } - return Ok(true); + return Ok(()); } else if !output_read_data { qdebug!("READ[{stream_id}]: {} bytes", data.len()); } else if let Ok(txt) = std::str::from_utf8(data) { @@ -313,7 +317,7 @@ impl StreamHandler for DownloadStreamHandler { } } - Ok(true) + Ok(()) } fn process_data_writable(&mut self, _client: &mut Http3Client, _stream_id: StreamId) {} @@ -335,18 +339,19 @@ impl StreamHandler for UploadStreamHandler { _fin: bool, data: &[u8], _output_read_data: bool, - ) -> Res { + ) -> Res<()> { if let Ok(txt) = std::str::from_utf8(data) { let trimmed_txt = txt.trim_end_matches(char::from(0)); - let parsed: usize = trimmed_txt.parse().unwrap(); + let parsed: usize = trimmed_txt.parse().map_err(|_| Error::InvalidInput)?; if parsed == self.data.len() { let upload_time = Instant::now().duration_since(self.start); qinfo!("Stream ID: {stream_id:?}, Upload time: {upload_time:?}"); } + Ok(()) } else { - panic!("Unexpected data [{stream_id}]: 0x{}", hex(data)); + qerror!("Unexpected data [{stream_id}]: 0x{}", hex(data)); + Err(crate::client::Error::Http3Error(Error::InvalidInput)) } - Ok(true) } fn process_data_writable(&mut self, client: &mut Http3Client, stream_id: StreamId) { diff --git a/third_party/rust/neqo-bin/src/client/mod.rs b/third_party/rust/neqo-bin/src/client/mod.rs index 9da2800d8077..16bbb7ecc35e 100644 --- a/third_party/rust/neqo-bin/src/client/mod.rs +++ b/third_party/rust/neqo-bin/src/client/mod.rs @@ -4,7 +4,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(clippy::future_not_send)] +#![expect(clippy::unwrap_used, reason = "This is example code.")] use std::{ collections::{HashMap, VecDeque}, @@ -104,7 +104,10 @@ type Res = Result; #[derive(Debug, Parser)] #[command(author, version, about, long_about = None)] -#[allow(clippy::struct_excessive_bools)] // Not a good use of that lint. +#[expect( + clippy::struct_excessive_bools, + reason = "Not a good use of that lint." +)] pub struct Args { #[command(flatten)] shared: SharedArgs, @@ -180,7 +183,7 @@ pub struct Args { impl Args { #[must_use] #[cfg(any(test, feature = "bench"))] - #[allow(clippy::missing_panics_doc)] + #[expect(clippy::missing_panics_doc, reason = "This is example code.")] pub fn new(requests: &[usize], upload: bool) -> Self { use std::str::FromStr as _; Self { @@ -383,7 +386,7 @@ trait Client { fn process_output(&mut self, now: Instant) -> Output; fn process_multiple_input<'a>( &mut self, - dgrams: impl IntoIterator>, + dgrams: impl IntoIterator>, now: Instant, ); fn has_events(&self) -> bool; @@ -431,17 +434,14 @@ impl<'a, H: Handler> Runner<'a, H> { continue; } - #[allow(clippy::match_same_arms)] match (handler_done, self.client.is_closed()?) { - // more work - (false, _) => {} + // more work; or no more work, already closing connection + (true, CloseState::Closing) | (false, _) => {} // no more work, closing connection (true, CloseState::NotClosing) => { self.client.close(Instant::now(), 0, "kthxbye!"); continue; } - // no more work, already closing connection - (true, CloseState::Closing) => {} // no more work, connection closed, terminating (true, CloseState::Closed) => break, } @@ -464,10 +464,19 @@ impl<'a, H: Handler> Runner<'a, H> { async fn process_output(&mut self) -> Result<(), io::Error> { loop { match self.client.process_output(Instant::now()) { - Output::Datagram(dgram) => { - self.socket.writable().await?; - self.socket.send(&dgram)?; - } + Output::Datagram(dgram) => loop { + // Optimistically attempt sending datagram. In case the OS + // buffer is full, wait till socket is writable then try + // again. + match self.socket.send(&dgram) { + Ok(()) => break, + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + self.socket.writable().await?; + // Now try again. + } + e @ Err(_) => return e, + } + }, Output::Callback(new_timeout) => { qdebug!("Setting timeout of {new_timeout:?}"); self.timeout = Some(Box::pin(tokio::time::sleep(new_timeout))); @@ -542,6 +551,12 @@ fn urls_by_origin(urls: &[Url]) -> impl Iterator Res<()> { neqo_common::log::init( args.shared diff --git a/third_party/rust/neqo-bin/src/lib.rs b/third_party/rust/neqo-bin/src/lib.rs index 1e25f8690f2f..90020b740de5 100644 --- a/third_party/rust/neqo-bin/src/lib.rs +++ b/third_party/rust/neqo-bin/src/lib.rs @@ -4,9 +4,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(clippy::missing_panics_doc)] -#![allow(clippy::missing_errors_doc)] - use std::{ fmt::{self, Display}, net::{SocketAddr, ToSocketAddrs as _}, @@ -168,8 +165,8 @@ impl QuicParameters { assert_eq!( opt.is_some(), addr.is_some(), - "unable to resolve '{}' to an {v} address", - opt.as_ref().unwrap(), + "unable to resolve '{:?}' to an {v} address", + opt.as_ref()?, ); addr } diff --git a/third_party/rust/neqo-bin/src/server/http09.rs b/third_party/rust/neqo-bin/src/server/http09.rs index 7c4fb792db8b..72b95adb1782 100644 --- a/third_party/rust/neqo-bin/src/server/http09.rs +++ b/third_party/rust/neqo-bin/src/server/http09.rs @@ -4,6 +4,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect(clippy::unwrap_used, reason = "This is example code.")] + use std::{borrow::Cow, cell::RefCell, collections::HashMap, fmt::Display, rc::Rc, time::Instant}; use neqo_common::{event::Provider as _, hex, qdebug, qerror, qinfo, qwarn, Datagram}; @@ -55,10 +57,10 @@ impl HttpServer { server.set_validation(ValidateAddress::Always); } if args.ech { - let (sk, pk) = generate_ech_keys().expect("generate ECH keys"); + let (sk, pk) = generate_ech_keys().map_err(|_| Error::Internal)?; server .enable_ech(random::<1>()[0], "public.example", &sk, &pk) - .expect("enable ECH"); + .map_err(|_| Error::Internal)?; let cfg = server.ech_config(); qinfo!("ECHConfigList: {}", hex(cfg)); } @@ -70,9 +72,9 @@ impl HttpServer { read_state: HashMap::new(), is_qns_test, regex: if is_qns_test { - Regex::new(r"GET +/(\S+)(?:\r)?\n").unwrap() + Regex::new(r"GET +/(\S+)(?:\r)?\n").map_err(|_| Error::Internal)? } else { - Regex::new(r"GET +/(\d+)(?:\r)?\n").unwrap() + Regex::new(r"GET +/(\d+)(?:\r)?\n").map_err(|_| Error::Internal)? }, read_buffer: vec![0; STREAM_IO_BUFFER_SIZE], }) @@ -185,14 +187,15 @@ impl HttpServer { } impl super::HttpServer for HttpServer { - fn process(&mut self, dgram: Option>, now: Instant) -> Output { + fn process(&mut self, dgram: Option>, now: Instant) -> Output { self.server.process(dgram, now) } fn process_events(&mut self, now: Instant) { - // `ActiveConnectionRef` `Hash` implementation doesn’t access any of the interior mutable - // types. - #[allow(clippy::mutable_key_type)] + #[expect( + clippy::mutable_key_type, + reason = "ActiveConnectionRef::Hash doesn't access any of the interior mutable types" + )] let active_conns = self.server.active_connections(); for acr in active_conns { loop { diff --git a/third_party/rust/neqo-bin/src/server/http3.rs b/third_party/rust/neqo-bin/src/server/http3.rs index c22b95c6fd5a..13f07706e023 100644 --- a/third_party/rust/neqo-bin/src/server/http3.rs +++ b/third_party/rust/neqo-bin/src/server/http3.rs @@ -4,6 +4,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect(clippy::unwrap_used, reason = "This is example code.")] + use std::{ cell::RefCell, collections::HashMap, @@ -80,7 +82,7 @@ impl Display for HttpServer { } impl super::HttpServer for HttpServer { - fn process(&mut self, dgram: Option>, now: Instant) -> neqo_http3::Output { + fn process(&mut self, dgram: Option>, now: Instant) -> neqo_http3::Output { self.server.process(dgram, now) } diff --git a/third_party/rust/neqo-bin/src/server/mod.rs b/third_party/rust/neqo-bin/src/server/mod.rs index 2d8db660eb3f..3e9621eda99c 100644 --- a/third_party/rust/neqo-bin/src/server/mod.rs +++ b/third_party/rust/neqo-bin/src/server/mod.rs @@ -4,7 +4,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(clippy::future_not_send)] +#![allow( + clippy::module_name_repetitions, + reason = "" +)] +#![expect( + clippy::unwrap_used, + clippy::future_not_send, + clippy::missing_errors_doc, + clippy::missing_panics_doc, + reason = "This is example code." +)] use std::{ cell::RefCell, @@ -190,14 +200,12 @@ fn qns_read_response(filename: &str) -> Result, io::Error> { fs::read(path) } -#[allow(clippy::module_name_repetitions)] pub trait HttpServer: Display { - fn process(&mut self, dgram: Option>, now: Instant) -> Output; + fn process(&mut self, dgram: Option>, now: Instant) -> Output; fn process_events(&mut self, now: Instant); fn has_events(&self) -> bool; } -#[allow(clippy::module_name_repetitions)] pub struct ServerRunner { now: Box Instant>, server: Box, @@ -242,14 +250,25 @@ impl ServerRunner { timeout: &mut Option>>, sockets: &mut [(SocketAddr, crate::udp::Socket)], now: &dyn Fn() -> Instant, - mut input_dgram: Option>, + mut input_dgram: Option>, ) -> Result<(), io::Error> { loop { match server.process(input_dgram.take(), now()) { Output::Datagram(dgram) => { let socket = Self::find_socket(sockets, dgram.source()); - socket.writable().await?; - socket.send(&dgram)?; + loop { + // Optimistically attempt sending datagram. In case the + // OS buffer is full, wait till socket is writable then + // try again. + match socket.send(&dgram) { + Ok(()) => break, + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + socket.writable().await?; + // Now try again. + } + e @ Err(_) => return e, + } + } } Output::Callback(new_timeout) => { qdebug!("Setting timeout of {new_timeout:?}"); diff --git a/third_party/rust/neqo-bin/src/udp.rs b/third_party/rust/neqo-bin/src/udp.rs index bd8d0eef8567..5cfcd71f91ae 100644 --- a/third_party/rust/neqo-bin/src/udp.rs +++ b/third_party/rust/neqo-bin/src/udp.rs @@ -4,9 +4,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect(clippy::missing_errors_doc, reason = "Passing up tokio errors.")] + use std::{io, net::SocketAddr}; -use neqo_common::Datagram; +use neqo_common::{qdebug, Datagram}; use neqo_udp::{DatagramIter, RecvBuf}; /// Ideally this would live in [`neqo-udp`]. [`neqo-udp`] is used in Firefox. @@ -24,10 +26,36 @@ pub struct Socket { impl Socket { /// Create a new [`Socket`] bound to the provided address, not managed externally. pub fn bind(addr: A) -> Result { + const ONE_MB: usize = 1 << 20; let socket = std::net::UdpSocket::bind(addr)?; + let state = quinn_udp::UdpSocketState::new((&socket).into())?; + + let send_buf_before = state.send_buffer_size((&socket).into())?; + // FIXME: We need to experiment if increasing this actually improves performance. + // Also, on BSD and Apple targets, this seems to increase the `net.inet.udp.maxdgram` + // sysctl, which is not the same as the socket buffer. + // if send_buf_before < ONE_MB { + // state.set_send_buffer_size((&socket).into(), ONE_MB)?; + // let send_buf_after = state.send_buffer_size((&socket).into())?; + // qdebug!("Increasing socket send buffer size from {send_buf_before} to {ONE_MB}, now: + // {send_buf_after}"); } else { + // qdebug!("Default socket send buffer size is {send_buf_before}, not changing"); + // } + qdebug!("Default socket send buffer size is {send_buf_before}"); + + let recv_buf_before = state.recv_buffer_size((&socket).into())?; + if recv_buf_before < ONE_MB { + // Same as Firefox. + // + state.set_recv_buffer_size((&socket).into(), ONE_MB)?; + let recv_buf_after = state.recv_buffer_size((&socket).into())?; + qdebug!("Increasing socket recv buffer size from {recv_buf_before} to {ONE_MB}, now: {recv_buf_after}"); + } else { + qdebug!("Default socket receive buffer size is {recv_buf_before}, not changing"); + } Ok(Self { - state: quinn_udp::UdpSocketState::new((&socket).into())?, + state, inner: tokio::net::UdpSocket::from_std(socket)?, }) } diff --git a/third_party/rust/neqo-common/.cargo-checksum.json b/third_party/rust/neqo-common/.cargo-checksum.json index da3bf29dca82..d7c80530d3f5 100644 --- a/third_party/rust/neqo-common/.cargo-checksum.json +++ b/third_party/rust/neqo-common/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"34eca5cf0f6408d36c215d7ca439aad5a496fb154bd4d6cb3faf0ddbcf7d2c34","benches/decoder.rs":"e7fab506974d7b6b4f41fe51036151b15f0d693b7e45b80cf9e2141bb1f6298f","build.rs":"ee5dc521f3d8e18c2b617192d6b6e678f7f2f9886fdd34c0c1c5ef841419b248","src/codec.rs":"8aea4a5041d1b06e4928d29fefcc8166d515b72f9a744e572d3c92b90e9ea268","src/datagram.rs":"e8bf176d3b120028731388c17344d03b8195e5fd70f4d03e37144ac5ae5951f5","src/event.rs":"289cf8e265c33e7cded58820ac81e5b575e3f84dd52fa18b0761f4094fb361c0","src/fuzz.rs":"9e0f2dca1832ef49b93b214e8d5f1ca2f5f8cb84a856fead344f62a722c370db","src/header.rs":"a316f48735375da268142ad9ac3430d240162c9df67114546f4a094c25a10024","src/hrtime.rs":"754f90ae3f3839e59ccaa34a9f07a2742ec7080f2df539f4b7691c7771dd4856","src/incrdecoder.rs":"2128bb6aa737932b484cdff8213efe8eac46004ef2d9219b6f48ac4d664297ac","src/lib.rs":"002f6a740464b618036e699db4ebea1fc803b9c9c154c0478f6f8721932f4300","src/log.rs":"2ea3f00b1776e085cbf6b46dc7489259b4e58a2dada7edaf94e746de3defb222","src/qlog.rs":"f335b4f4340ae0bfaeb6742bd5a2cb8b6f16292a40b410ed3f72ce309b171106","src/tos.rs":"206410cf0d164a0c1a1c3de19ddcd224e311601707bedc7af100a30a950d12f9","tests/log.rs":"671a963f938599b76c0678f3931592e1782765ed4ea13e6cbfec2ab97c36e2c9"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"eb681eeb4daecac76e7fc32d2ec1b1d28d37acbfbf4e800e28533a3f9426db58","benches/decoder.rs":"3b03abd08c064d11c07e6d4eaf041873c282adf93e9bc76e40f2f0137e342929","build.rs":"d9accad1f92a1d82aff73a588269342db882918173e8d9b2b914c514e42e2839","src/codec.rs":"b56abcf6fc76d7c24a6f25e0df556fa3c47a37249b43ae97451944082d344a30","src/datagram.rs":"88ef237b95b4ce10abe5e8e4740a4a8178f19146fc82c49053d3b62819ac428a","src/event.rs":"289cf8e265c33e7cded58820ac81e5b575e3f84dd52fa18b0761f4094fb361c0","src/fuzz.rs":"9e0f2dca1832ef49b93b214e8d5f1ca2f5f8cb84a856fead344f62a722c370db","src/header.rs":"b561dffd52ec8909297ec67ac5f75150dfca73399111e709cf6ea7a34998fca5","src/hrtime.rs":"7096fd12ccc33566aac58f19a4e7439690b2fa38c258584946f76a422ab98087","src/incrdecoder.rs":"029081f0ae19db49c3278c865f22584fc24315169e5ffc1bd5a0087e8c0d38b9","src/lib.rs":"5f15b8b96cd8935e4cc231bb37d45458794ffe23eea0db1b37e42ea7346ac10d","src/log.rs":"61a9b24bf6bf1493da67082bcf7fef8fe55f0a23d7f2a9ad13748982c54c85e2","src/qlog.rs":"3c6f403f0ad2b34fc7ba63b1338bc0855bc232a2b5dd5c1039846b10af2b1d35","src/tos.rs":"108ebfcadf172aae1ba1c722316080b70ec017bf9c866f1ab8d315231d04fd09","tests/log.rs":"671a963f938599b76c0678f3931592e1782765ed4ea13e6cbfec2ab97c36e2c9"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-common/Cargo.toml b/third_party/rust/neqo-common/Cargo.toml index 682b71842d2f..5d5a64b084fe 100644 --- a/third_party/rust/neqo-common/Cargo.toml +++ b/third_party/rust/neqo-common/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.76.0" +rust-version = "1.82.0" name = "neqo-common" -version = "0.12.2" +version = "0.13.1" authors = ["The Neqo Authors "] build = "build.rs" autolib = false @@ -44,7 +44,7 @@ bench = [ "neqo-crypto/bench", "test-fixture/bench", ] -build-fuzzing-corpus = ["hex"] +build-fuzzing-corpus = ["hex/alloc"] ci = [] test-fixture = [] @@ -73,7 +73,6 @@ default-features = false [dependencies.hex] version = "0.4" -features = ["alloc"] optional = true default-features = false @@ -82,7 +81,12 @@ version = "0.4" default-features = false [dependencies.qlog] -version = "0.13" +version = "0.15.1" +default-features = false + +[dependencies.strum] +version = "0.26" +features = ["derive"] default-features = false [dev-dependencies.criterion] @@ -94,7 +98,6 @@ path = "../neqo-crypto" [dev-dependencies.regex] version = "1.9" -features = ["unicode-perl"] default-features = false [dev-dependencies.test-fixture] @@ -106,22 +109,56 @@ features = ["Win32_Media"] default-features = false [lints.clippy] +allow_attributes = "warn" +allow_attributes_without_reason = "warn" cfg_not_test = "warn" clone_on_ref_ptr = "warn" create_dir = "warn" +dbg_macro = "warn" +empty_drop = "warn" +empty_enum_variants_with_brackets = "warn" +filetype_is_file = "warn" +float_cmp_const = "warn" +fn_to_numeric_cast_any = "warn" get_unwrap = "warn" if_then_some_else_none = "warn" +infinite_loop = "warn" +large_include_file = "warn" +let_underscore_must_use = "warn" +let_underscore_untyped = "warn" +literal_string_with_formatting_args = "allow" +lossy_float_literal = "warn" +mem_forget = "warn" +mixed_read_write_in_expression = "warn" +module_name_repetitions = "warn" multiple_crate_versions = "allow" multiple_inherent_impl = "warn" +mutex_atomic = "warn" +mutex_integer = "warn" +needless_raw_strings = "warn" pathbuf_init_then_push = "warn" +pub_without_shorthand = "warn" +rc_buffer = "warn" +rc_mutex = "warn" redundant_type_annotations = "warn" ref_patterns = "warn" renamed_function_params = "warn" +rest_pat_in_fully_bound_structs = "warn" +self_named_module_files = "warn" semicolon_inside_block = "warn" +string_lit_chars_any = "warn" +string_to_string = "warn" +suspicious_xor_used_as_pow = "warn" try_err = "warn" +unnecessary_safety_comment = "warn" +unnecessary_safety_doc = "warn" +unnecessary_self_imports = "warn" unneeded_field_pattern = "warn" unused_result_ok = "warn" unused_trait_names = "warn" +unwrap_in_result = "warn" +unwrap_used = "warn" +verbose_file_reads = "warn" [lints.clippy.cargo] level = "warn" @@ -138,7 +175,6 @@ priority = -1 [lints.rust] absolute_paths_not_starting_with_crate = "warn" ambiguous_negative_literals = "warn" -closure_returning_async_block = "warn" explicit_outlives_requirements = "warn" macro_use_extern_crate = "warn" missing_abi = "warn" @@ -150,3 +186,4 @@ unit_bindings = "warn" unused_import_braces = "warn" unused_lifetimes = "warn" unused_macro_rules = "warn" +unused_qualifications = "warn" diff --git a/third_party/rust/neqo-common/benches/decoder.rs b/third_party/rust/neqo-common/benches/decoder.rs index e15b1bec647e..8e7b7f5047b8 100644 --- a/third_party/rust/neqo-common/benches/decoder.rs +++ b/third_party/rust/neqo-common/benches/decoder.rs @@ -4,6 +4,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect(clippy::unwrap_used, reason = "OK in a bench.")] + use criterion::{black_box, criterion_group, criterion_main, Criterion}; use neqo_common::Decoder; use neqo_crypto::{init, randomize}; diff --git a/third_party/rust/neqo-common/build.rs b/third_party/rust/neqo-common/build.rs index 473ae6073848..e42684f929a5 100644 --- a/third_party/rust/neqo-common/build.rs +++ b/third_party/rust/neqo-common/build.rs @@ -4,6 +4,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect(clippy::unwrap_used, reason = "OK in a build script.")] + use std::env; fn main() { diff --git a/third_party/rust/neqo-common/src/codec.rs b/third_party/rust/neqo-common/src/codec.rs index f772c5949b38..835221dbf497 100644 --- a/third_party/rust/neqo-common/src/codec.rs +++ b/third_party/rust/neqo-common/src/codec.rs @@ -47,6 +47,7 @@ impl<'a> Decoder<'a> { /// Only use this for tests because we panic rather than reporting a result. #[cfg(any(test, feature = "test-fixture"))] fn skip_inner(&mut self, n: Option) { + #[expect(clippy::unwrap_used, reason = "Only used in tests.")] self.skip(usize::try_from(n.expect("invalid length")).unwrap()); } @@ -111,7 +112,7 @@ impl<'a> Decoder<'a> { /// unsigned integer types: `u8`, `u16`, `u32`, or `u64`. /// Signed types will fail if the high bit is set. pub fn decode_uint>(&mut self) -> Option { - let v = self.decode_n(std::mem::size_of::()); + let v = self.decode_n(size_of::()); v.and_then(|v| T::try_from(v).ok()) } @@ -161,7 +162,6 @@ impl<'a> Decoder<'a> { // Implement `AsRef` for `Decoder` so that values can be examined without // moving the cursor. impl<'a> AsRef<[u8]> for Decoder<'a> { - #[must_use] fn as_ref(&self) -> &'a [u8] { &self.buf[self.offset..] } @@ -174,7 +174,6 @@ impl Debug for Decoder<'_> { } impl<'a> From<&'a [u8]> for Decoder<'a> { - #[must_use] fn from(buf: &'a [u8]) -> Self { Decoder::new(buf) } @@ -184,14 +183,12 @@ impl<'a, T> From<&'a T> for Decoder<'a> where T: AsRef<[u8]>, { - #[must_use] fn from(buf: &'a T) -> Self { Decoder::new(buf.as_ref()) } } impl<'b> PartialEq> for Decoder<'_> { - #[must_use] fn eq(&self, other: &Decoder<'b>) -> bool { self.buf == other.buf } @@ -227,7 +224,7 @@ impl Encoder { /// When `len` doesn't fit in a `u64`. #[must_use] pub fn vvec_len(len: usize) -> usize { - Self::varint_len(u64::try_from(len).unwrap()) + len + Self::varint_len(u64::try_from(len).expect("usize should fit into u64")) + len } /// Default construction of an empty buffer. @@ -286,6 +283,7 @@ impl Encoder { let mut enc = Self::with_capacity(cap); for i in 0..cap { + #[expect(clippy::unwrap_used, reason = "Only used in tests.")] let v = u8::from_str_radix(&s[i * 2..i * 2 + 2], 16).unwrap(); enc.encode_byte(v); } @@ -341,8 +339,11 @@ impl Encoder { /// /// When `v` is longer than 2^64. pub fn encode_vec(&mut self, n: usize, v: &[u8]) -> &mut Self { - self.encode_uint(n, u64::try_from(v.as_ref().len()).unwrap()) - .encode(v) + self.encode_uint( + n, + u64::try_from(v.as_ref().len()).expect("v is longer than 2^64"), + ) + .encode(v) } /// Encode a vector in TLS style using a closure for the contents. @@ -350,7 +351,10 @@ impl Encoder { /// # Panics /// /// When `f()` returns a length larger than `2^8n`. - #[allow(clippy::cast_possible_truncation)] + #[expect( + clippy::cast_possible_truncation, + reason = "AND'ing with 0xff makes this OK." + )] pub fn encode_vec_with(&mut self, n: usize, f: F) -> &mut Self { let start = self.buf.len(); self.buf.resize(self.buf.len() + n, 0); @@ -369,7 +373,7 @@ impl Encoder { /// /// When `v` is longer than 2^64. pub fn encode_vvec(&mut self, v: &[u8]) -> &mut Self { - self.encode_varint(u64::try_from(v.as_ref().len()).unwrap()) + self.encode_varint(u64::try_from(v.as_ref().len()).expect("v is longer than 2^64")) .encode(v) } @@ -447,14 +451,12 @@ impl AsMut<[u8]> for Encoder { } impl<'a> From> for Encoder { - #[must_use] fn from(dec: Decoder<'a>) -> Self { Self::from(&dec.buf[dec.offset..]) } } impl From<&[u8]> for Encoder { - #[must_use] fn from(buf: &[u8]) -> Self { Self { buf: Vec::from(buf), @@ -463,7 +465,6 @@ impl From<&[u8]> for Encoder { } impl From for Vec { - #[must_use] fn from(buf: Encoder) -> Self { buf.buf } @@ -664,6 +665,7 @@ mod tests { } #[test] + #[cfg(target_pointer_width = "64")] // Test does not compile on 32-bit targets. #[should_panic(expected = "Varint value too large")] fn encoded_vvec_length_oob() { _ = Encoder::vvec_len(1 << 62); diff --git a/third_party/rust/neqo-common/src/datagram.rs b/third_party/rust/neqo-common/src/datagram.rs index c3b8713c695f..f2a33caf5dd7 100644 --- a/third_party/rust/neqo-common/src/datagram.rs +++ b/third_party/rust/neqo-common/src/datagram.rs @@ -4,7 +4,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{net::SocketAddr, ops::Deref}; +use std::{ + net::SocketAddr, + ops::{Deref, DerefMut}, +}; use crate::{hex_with_len, IpTos}; @@ -47,7 +50,6 @@ impl> Datagram { } } -#[cfg(test)] impl + AsRef<[u8]>> AsMut<[u8]> for Datagram { fn as_mut(&mut self) -> &mut [u8] { self.d.as_mut() @@ -65,9 +67,14 @@ impl Datagram> { } } +impl + AsMut<[u8]>> DerefMut for Datagram { + fn deref_mut(&mut self) -> &mut Self::Target { + AsMut::<[u8]>::as_mut(self) + } +} + impl> Deref for Datagram { type Target = [u8]; - #[must_use] fn deref(&self) -> &Self::Target { AsRef::<[u8]>::as_ref(self) } @@ -86,9 +93,9 @@ impl> std::fmt::Debug for Datagram { } } -impl<'a> Datagram<&'a [u8]> { +impl<'a> Datagram<&'a mut [u8]> { #[must_use] - pub const fn from_slice(src: SocketAddr, dst: SocketAddr, tos: IpTos, d: &'a [u8]) -> Self { + pub fn from_slice(src: SocketAddr, dst: SocketAddr, tos: IpTos, d: &'a mut [u8]) -> Self { Self { src, dst, tos, d } } diff --git a/third_party/rust/neqo-common/src/header.rs b/third_party/rust/neqo-common/src/header.rs index a480eb67ca7c..ff1eed42176a 100644 --- a/third_party/rust/neqo-common/src/header.rs +++ b/third_party/rust/neqo-common/src/header.rs @@ -36,11 +36,21 @@ impl Header { ) } + #[allow( + clippy::allow_attributes, + clippy::missing_const_for_fn, + reason = "TODO: False positive on nightly." + )] #[must_use] pub fn name(&self) -> &str { &self.name } + #[allow( + clippy::allow_attributes, + clippy::missing_const_for_fn, + reason = "TODO: False positive on nightly." + )] #[must_use] pub fn value(&self) -> &str { &self.value diff --git a/third_party/rust/neqo-common/src/hrtime.rs b/third_party/rust/neqo-common/src/hrtime.rs index b4f23d73cfbb..3f44c770e22a 100644 --- a/third_party/rust/neqo-common/src/hrtime.rs +++ b/third_party/rust/neqo-common/src/hrtime.rs @@ -70,7 +70,7 @@ impl PeriodSet { fn min(&self) -> Option { for (i, v) in self.counts.iter().enumerate() { if *v > 0 { - return Some(Period(u8::try_from(i).unwrap() + Period::MIN.0)); + return Some(Period(u8::try_from(i).ok()? + Period::MIN.0)); } } None @@ -78,7 +78,7 @@ impl PeriodSet { } #[cfg(target_os = "macos")] -#[allow(non_camel_case_types)] +#[expect(non_camel_case_types, reason = "These are C types.")] mod mac { use std::ptr::addr_of_mut; @@ -124,9 +124,9 @@ mod mac { } const THREAD_TIME_CONSTRAINT_POLICY: thread_policy_flavor_t = 2; - #[allow(clippy::cast_possible_truncation)] + #[expect(clippy::cast_possible_truncation, reason = "These are C types.")] const THREAD_TIME_CONSTRAINT_POLICY_COUNT: mach_msg_type_number_t = - (std::mem::size_of::() / std::mem::size_of::()) + (size_of::() / size_of::()) as mach_msg_type_number_t; // These function definitions are taken from a comment in . @@ -179,7 +179,11 @@ mod mac { /// Create a realtime policy and set it. pub fn set_realtime(base: f64) { - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + #[expect( + clippy::cast_possible_truncation, + clippy::cast_sign_loss, + reason = "These are C types." + )] let policy = thread_time_constraint_policy { period: base as u32, // Base interval computation: (base * 0.5) as u32, @@ -302,7 +306,10 @@ impl Time { } #[cfg(all(not(target_os = "macos"), not(target_os = "windows")))] - #[allow(clippy::unused_self)] + #[expect( + clippy::unused_self, + reason = "Not used on platforms other than macOS and Windows." + )] const fn start(&self) {} #[cfg(windows)] @@ -313,7 +320,10 @@ impl Time { } #[cfg(not(target_os = "windows"))] - #[allow(clippy::unused_self)] + #[expect( + clippy::unused_self, + reason = "Not used on platforms other than Windows." + )] const fn stop(&self) {} fn update(&mut self) { @@ -372,7 +382,8 @@ impl Drop for Time { // Only run these tests in CI on Linux, where the timer accuracies are OK enough to pass the tests, // but only when not running sanitizers. -#[cfg(all(test, target_os = "linux", not(neqo_sanitize)))] +#[cfg(all(target_os = "linux", not(neqo_sanitize)))] +#[cfg(test)] mod test { use std::{ thread::{sleep, spawn}, diff --git a/third_party/rust/neqo-common/src/incrdecoder.rs b/third_party/rust/neqo-common/src/incrdecoder.rs index f094d25f1c9b..27d7217c7b0d 100644 --- a/third_party/rust/neqo-common/src/incrdecoder.rs +++ b/third_party/rust/neqo-common/src/incrdecoder.rs @@ -31,7 +31,7 @@ impl IncrementalDecoderUint { if amount < 8 { self.v <<= amount * 8; } - self.v |= dv.decode_n(amount).unwrap(); + self.v |= dv.decode_n(amount)?; *r -= amount; (*r == 0).then_some(self.v) } else { @@ -89,7 +89,7 @@ impl IncrementalDecoderBuffer { /// Never; but rust doesn't know that. pub fn consume(&mut self, dv: &mut Decoder) -> Option> { let amount = min(self.remaining, dv.remaining()); - let b = dv.decode(amount).unwrap(); + let b = dv.decode(amount)?; self.v.extend_from_slice(b); self.remaining -= amount; (self.remaining == 0).then(|| mem::take(&mut self.v)) diff --git a/third_party/rust/neqo-common/src/lib.rs b/third_party/rust/neqo-common/src/lib.rs index 1e7a53ad1953..5a639cf809b1 100644 --- a/third_party/rust/neqo-common/src/lib.rs +++ b/third_party/rust/neqo-common/src/lib.rs @@ -4,8 +4,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(clippy::module_name_repetitions)] // This lint doesn't work here. - mod codec; mod datagram; pub mod event; @@ -21,6 +19,7 @@ pub mod tos; use std::fmt::Write as _; use enum_map::Enum; +use strum::Display; #[cfg(feature = "build-fuzzing-corpus")] pub use self::fuzz::write_item_to_fuzzing_corpus; @@ -81,7 +80,7 @@ pub const fn const_min(a: usize, b: usize) -> usize { [a, b][(a >= b) as usize] } -#[derive(Debug, PartialEq, Eq, Copy, Clone, Enum)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Enum, Display)] /// Client or Server. pub enum Role { Client, @@ -98,12 +97,6 @@ impl Role { } } -impl ::std::fmt::Display for Role { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "{self:?}") - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum MessageType { Request, diff --git a/third_party/rust/neqo-common/src/log.rs b/third_party/rust/neqo-common/src/log.rs index ac331ede08ee..257884cf63a1 100644 --- a/third_party/rust/neqo-common/src/log.rs +++ b/third_party/rust/neqo-common/src/log.rs @@ -4,8 +4,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(clippy::module_name_repetitions)] - use std::{ io::Write as _, sync::{Once, OnceLock}, diff --git a/third_party/rust/neqo-common/src/qlog.rs b/third_party/rust/neqo-common/src/qlog.rs index 7401e21a5401..7e3d96b2d89c 100644 --- a/third_party/rust/neqo-common/src/qlog.rs +++ b/third_party/rust/neqo-common/src/qlog.rs @@ -4,6 +4,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow( + clippy::module_name_repetitions, + reason = "" +)] + use std::{ cell::RefCell, fmt::{self, Display}, @@ -20,7 +25,6 @@ use qlog::{ use crate::Role; -#[allow(clippy::module_name_repetitions)] #[derive(Debug, Clone, Default)] pub struct NeqoQlog { inner: Rc>>, diff --git a/third_party/rust/neqo-common/src/tos.rs b/third_party/rust/neqo-common/src/tos.rs index ed6a5d2724d2..8fa920d257ad 100644 --- a/third_party/rust/neqo-common/src/tos.rs +++ b/third_party/rust/neqo-common/src/tos.rs @@ -4,26 +4,29 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow( + clippy::module_name_repetitions, + reason = "" +)] + use std::fmt::Debug; use enum_map::Enum; +use strum::{EnumIter, FromRepr}; /// ECN (Explicit Congestion Notification) codepoints mapped to the /// lower 2 bits of the TOS field. /// -#[derive(Copy, Clone, PartialEq, Eq, Enum, Default, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Enum, Default, Debug, FromRepr, EnumIter)] #[repr(u8)] pub enum IpTosEcn { #[default] /// Not-ECT, Not ECN-Capable Transport, RFC3168 NotEct = 0b00, - /// ECT(1), ECN-Capable Transport(1), RFC8311 and RFC9331 Ect1 = 0b01, - /// ECT(0), ECN-Capable Transport(0), RFC3168 Ect0 = 0b10, - /// CE, Congestion Experienced, RFC3168 Ce = 0b11, } @@ -36,13 +39,7 @@ impl From for u8 { impl From for IpTosEcn { fn from(v: u8) -> Self { - match v & 0b0000_0011 { - 0b00 => Self::NotEct, - 0b01 => Self::Ect1, - 0b10 => Self::Ect0, - 0b11 => Self::Ce, - _ => unreachable!(), - } + Self::from_repr(v & 0b0000_0011).expect("all ECN values are covered") } } @@ -64,76 +61,54 @@ impl IpTosEcn { /// Diffserv codepoints, mapped to the upper six bits of the TOS field. /// -#[derive(Copy, Clone, PartialEq, Eq, Enum, Default, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Enum, Default, Debug, FromRepr)] #[repr(u8)] pub enum IpTosDscp { #[default] /// Class Selector 0, RFC2474 Cs0 = 0b0000_0000, - /// Class Selector 1, RFC2474 Cs1 = 0b0010_0000, - /// Class Selector 2, RFC2474 Cs2 = 0b0100_0000, - /// Class Selector 3, RFC2474 Cs3 = 0b0110_0000, - /// Class Selector 4, RFC2474 Cs4 = 0b1000_0000, - /// Class Selector 5, RFC2474 Cs5 = 0b1010_0000, - /// Class Selector 6, RFC2474 Cs6 = 0b1100_0000, - /// Class Selector 7, RFC2474 Cs7 = 0b1110_0000, - /// Assured Forwarding 11, RFC2597 Af11 = 0b0010_1000, - /// Assured Forwarding 12, RFC2597 Af12 = 0b0011_0000, - /// Assured Forwarding 13, RFC2597 Af13 = 0b0011_1000, - /// Assured Forwarding 21, RFC2597 Af21 = 0b0100_1000, - /// Assured Forwarding 22, RFC2597 Af22 = 0b0101_0000, - /// Assured Forwarding 23, RFC2597 Af23 = 0b0101_1000, - /// Assured Forwarding 31, RFC2597 Af31 = 0b0110_1000, - /// Assured Forwarding 32, RFC2597 Af32 = 0b0111_0000, - /// Assured Forwarding 33, RFC2597 Af33 = 0b0111_1000, - /// Assured Forwarding 41, RFC2597 Af41 = 0b1000_1000, - /// Assured Forwarding 42, RFC2597 Af42 = 0b1001_0000, - /// Assured Forwarding 43, RFC2597 Af43 = 0b1001_1000, - /// Expedited Forwarding, RFC3246 Ef = 0b1011_1000, - /// Capacity-Admitted Traffic, RFC5865 VoiceAdmit = 0b1011_0000, - /// Lower-Effort, RFC8622 Le = 0b0000_0100, } @@ -146,32 +121,7 @@ impl From for u8 { impl From for IpTosDscp { fn from(v: u8) -> Self { - match v & 0b1111_1100 { - 0b0000_0000 => Self::Cs0, - 0b0010_0000 => Self::Cs1, - 0b0100_0000 => Self::Cs2, - 0b0110_0000 => Self::Cs3, - 0b1000_0000 => Self::Cs4, - 0b1010_0000 => Self::Cs5, - 0b1100_0000 => Self::Cs6, - 0b1110_0000 => Self::Cs7, - 0b0010_1000 => Self::Af11, - 0b0011_0000 => Self::Af12, - 0b0011_1000 => Self::Af13, - 0b0100_1000 => Self::Af21, - 0b0101_0000 => Self::Af22, - 0b0101_1000 => Self::Af23, - 0b0110_1000 => Self::Af31, - 0b0111_0000 => Self::Af32, - 0b0111_1000 => Self::Af33, - 0b1000_1000 => Self::Af41, - 0b1001_0000 => Self::Af42, - 0b1001_1000 => Self::Af43, - 0b1011_1000 => Self::Ef, - 0b1011_0000 => Self::VoiceAdmit, - 0b0000_0100 => Self::Le, - _ => unreachable!(), - } + Self::from_repr(v & 0b1111_1100).expect("all DCSP values are covered") } } diff --git a/third_party/rust/neqo-crypto/.cargo-checksum.json b/third_party/rust/neqo-crypto/.cargo-checksum.json index 960276ca3fc3..7cb60eff1f7e 100644 --- a/third_party/rust/neqo-crypto/.cargo-checksum.json +++ b/third_party/rust/neqo-crypto/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"483cd040a7d91cc03ea3e497db33cc0fbafb7123520ea342a7825df079a6e72f","bindings/bindings.toml":"e7e4b75736cfcf4d52febacb99a6f6c6c7b1d648ed8bdc424648be876c850e91","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"dfc3b2c8038c4b1c69d7a10bd06c4226e36935e7597225aba26039f700cc8f4f","min_version.txt":"04b271df436ebebd03df52ef009d6814f6a64e55203988790a6fcee7b2dc27af","src/aead.rs":"018b826284ea4ddba7d65ff56f3ce9744e24ac8d26b1364b08f6e8b12b259be5","src/aead_null.rs":"81163fafef59bd2800bd0a078d53d0f05ee114f0e22165717823a5ff1cb908af","src/agent.rs":"6b6bcd735cb12d3e3ddebbb04ebd705d192a9cbce6e2a967e86e7b41cccf0a8d","src/agentio.rs":"237f85faacdb6ee5b3a6efa8a620fcf109094f5fd9dfb69d2c74986f11ccdb0e","src/auth.rs":"ced1a18f691894984244088020ea25dc1ee678603317f0c7dfc8b8842fa750b4","src/cert.rs":"4fdaa3834d8a72f41198449010fd5c3f6be6a54e429427c37bde5aab9421585c","src/constants.rs":"58e296e314825753b2ab1d6effe9a1386421dc568f6ebfa8e95a95acb87205da","src/ech.rs":"869e36414418b8747e6ebb45af24159c1908fc829439c16d79cdd89e355d2111","src/err.rs":"2366501e0b48933a6a2e1c5b934aa55108c093729c84878b45e1e012e4e45d51","src/exp.rs":"d953873e87430b1c84d4a83c8eb3815041f5585b210bbaf59ae2c4d0057f5edd","src/ext.rs":"cbf7d9f5ecabf4b8c9efd6c334637ab1596ec5266d38ab8d2d6ceae305283deb","src/hkdf.rs":"8745ba761be821c1819cedf6dfd91f8b3148c6718053a4a74f33eb50c7d0cc40","src/hp.rs":"510a4a7f278203aa306ead05608f99397edc3806dc22b0af9e28c665b43ae56c","src/lib.rs":"cfbf92759c6d1b888d89b9c28adbd96839bff60fc8106169a043eafce0f8a21e","src/min_version.rs":"c6e1f98b9f56db0622ac38c1be131c55acf4a0f09ed0d6283f4d6308e2d1301a","src/p11.rs":"120c45dc037c243a1551b79c7a32613acf22e2961f2ea1e11c73bbce9d1f76dc","src/prio.rs":"5cf0105e78b1db43c65283208174abc3714a41dbb4d5cd80ac547a5a5a7c627c","src/replay.rs":"5cda39bc8fa8a07c493b761b8dfb5cbc9f669f97a2df7832a028ab366b3426be","src/result.rs":"5a76688787741de7a935dbbab4bcb917d481d1c9c50a34df7e510036feb3da17","src/secrets.rs":"c09caca2bf7b60fc7855fc2ad56094a291cb0596308eadf46ab51af0e271a9f0","src/selfencrypt.rs":"80efac0f116b22d86f88f07d694ff2f822bd87b792b3dff8d6376a251394de39","src/ssl.rs":"450cf9fb327515de612b29e3a0f6e15499e6c0b523790e5986fd71a9ea5e76af","src/time.rs":"27d0185c16e150dc381cd6c01ef85fdf7881e5349386466e175d641aab9ab30f","tests/aead.rs":"e36ae77802df1ea6d17cfd1bd2178a3706089577d6fd1554ca86e748b8b235b9","tests/agent.rs":"cbd0011f1d33281883a45d433228221062424c94e86decade5697731c08a1c52","tests/ext.rs":"57af4e2df211fa8afdb73125d4344ef5c70c1ea4579107c3e6f5746308ee3e7b","tests/handshake.rs":"efae67a40f87419aea30c7ab7eb1007faf7f56a83dbf1a18e24fbc0cb92ec901","tests/hkdf.rs":"1d2098dc8398395864baf13e4886cfd1da6d36118727c3b264f457ee3da6b048","tests/hp.rs":"c74070a8f877aaa6305b9411f6e60d8b509b0ac1bef2988cc44b8a48552c953c","tests/init.rs":"3e15150c4b324c06ca5e8935618e4008da53dc0ef4b69325d150831e87dc0b63","tests/selfencrypt.rs":"8d10840b41629bf449a6b3a551377315e8a05ca26c6b041548748196652c5909"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"2dd521b9c64bcc1916751c27e89a542528652f742092feecb8866178cf9a8a72","bindings/bindings.toml":"e7e4b75736cfcf4d52febacb99a6f6c6c7b1d648ed8bdc424648be876c850e91","bindings/nspr_err.h":"2d5205d017b536c2d838bcf9bc4ec79f96dd50e7bb9b73892328781f1ee6629d","bindings/nspr_error.h":"e41c03c77b8c22046f8618832c9569fbcc7b26d8b9bbc35eea7168f35e346889","bindings/nspr_io.h":"085b289849ef0e77f88512a27b4d9bdc28252bd4d39c6a17303204e46ef45f72","bindings/nspr_time.h":"2e637fd338a5cf0fd3fb0070a47f474a34c2a7f4447f31b6875f5a9928d0a261","bindings/nss_ciphers.h":"95ec6344a607558b3c5ba8510f463b6295f3a2fb3f538a01410531045a5f62d1","bindings/nss_init.h":"ef49045063782fb612aff459172cc6a89340f15005808608ade5320ca9974310","bindings/nss_p11.h":"0b81e64fe6db49b2ecff94edd850be111ef99ec11220e88ceb1c67be90143a78","bindings/nss_secerr.h":"713e8368bdae5159af7893cfa517dabfe5103cede051dee9c9557c850a2defc6","bindings/nss_ssl.h":"af222fb957b989e392e762fa2125c82608a0053aff4fb97e556691646c88c335","bindings/nss_sslerr.h":"24b97f092183d8486f774cdaef5030d0249221c78343570d83a4ee5b594210ae","bindings/nss_sslopt.h":"b7807eb7abdad14db6ad7bc51048a46b065a0ea65a4508c95a12ce90e59d1eea","build.rs":"97fb6b8f8bb76dc1ed47988025645da618f3301871827d2a98d57254f7c62d5b","min_version.txt":"0f9ddf9ddaeb5137a5ab3d238d06286822f9579b1f46ba76312a8c6d76176500","src/aead.rs":"08d7cad82e3bec32661cfd1689e6611b30ae328ec88481cb32201dd255777365","src/aead_null.rs":"a766e2f71fd8b77a8f81bc60aaaafcffb6aef1f0a1f39ea07fef45b3696718ce","src/agent.rs":"19d9ee826e30c29ca8680e9ec767d19eac2326323f61b2a19bb62874990bf349","src/agentio.rs":"82f0cdececcb475c7b8639c993d4479bce7ac5fdf64b0d560f4b2fd356d03b03","src/auth.rs":"7a1524bef0a0c71616f5ee8b3976d66201210b809271bcf5d06c0e560ae482af","src/cert.rs":"4fdaa3834d8a72f41198449010fd5c3f6be6a54e429427c37bde5aab9421585c","src/constants.rs":"83606aeb646b2833a8094f9d980c266ecc3e8cb40c93a4820da221988319dd1a","src/ech.rs":"19d16af5a30e2060a8942a72487bd820c0d9c62ff1d3c490871752c56781c44b","src/err.rs":"b1e76e595326598a9bac45859f337ad9fb9a92ba9461d8c87250556a2629e7b6","src/exp.rs":"30f91d321439edc75c7f9a595ef5a0064918826d51ab15642db211472694009c","src/ext.rs":"7486595a24d39bd6c573e2229be345d13dbcd6911755ab6ab96d89ce7e263dd3","src/hkdf.rs":"76c5abc8b2d6ee12d8a86cd730af2cf47a59b2fbfd3b8a635a1826636156794d","src/hp.rs":"6adf4ad78b5a065ab7310c69ad239eec156256043e2c185bf60b9d1f12ab1be4","src/lib.rs":"3ab979c264a909e663c5ef140cd57013180745b99937671c73a9003ca6347f41","src/min_version.rs":"c6e1f98b9f56db0622ac38c1be131c55acf4a0f09ed0d6283f4d6308e2d1301a","src/p11.rs":"5c0759bb8ea5faad1a3d06fa7afb3dba114c93ea21981c85824d707f654d7c3d","src/prio.rs":"1858088afd2668e8fbff56959765b7d4df09342371b9282ade27bb4d7bd6ce69","src/replay.rs":"594ce92f368cbc5fb71ebfb62214f07d1e86df8e5ce94255d5593ffabb91cd03","src/result.rs":"5a76688787741de7a935dbbab4bcb917d481d1c9c50a34df7e510036feb3da17","src/secrets.rs":"f01ac665e3c65674865d0645fb1bf3e4579891bf392661e3de3c9f4621e454f0","src/selfencrypt.rs":"4f106465f582c38d3bb04cb5cbcbf65a349e3186784726d9f2bf511a4a4a35ee","src/ssl.rs":"04950bb534b5304eb417909a3a39ebaa9be234c7c13eacdc41c00a8edab1b09f","src/time.rs":"22989caf3dab85cfe955cc279fcca98a6df02d14fcd0e93cac7b39374b8b5763","tests/aead.rs":"e36ae77802df1ea6d17cfd1bd2178a3706089577d6fd1554ca86e748b8b235b9","tests/agent.rs":"fb95a2d5c86ce3fafcb127cd0a2a163e5ee70baf09b2c8483e4d1fb25644cee2","tests/ext.rs":"57af4e2df211fa8afdb73125d4344ef5c70c1ea4579107c3e6f5746308ee3e7b","tests/handshake.rs":"c06ed3d27b0f84b03ff0d0356a16601768821d9860cab81a49fea3eebb3091f2","tests/hkdf.rs":"1d2098dc8398395864baf13e4886cfd1da6d36118727c3b264f457ee3da6b048","tests/hp.rs":"1ad88108b6d8c5d078fc7bb2a4337a54f637d4e149db750f4916032d90aa64a7","tests/init.rs":"3cfe8411ca31ad7dfb23822bb1570e1a5b2b334857173bdd7df086b65b81d95a","tests/selfencrypt.rs":"b65aed70e83dce660017159fc8a956d3b52e0807b590ad8d0a3a4265caa8c1fa"},"package":null} \ No newline at end of file diff --git a/third_party/rust/neqo-crypto/Cargo.toml b/third_party/rust/neqo-crypto/Cargo.toml index 4e9542222983..806e4b52d2d2 100644 --- a/third_party/rust/neqo-crypto/Cargo.toml +++ b/third_party/rust/neqo-crypto/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.76.0" +rust-version = "1.82.0" name = "neqo-crypto" -version = "0.12.2" +version = "0.13.1" authors = ["The Neqo Authors "] build = "build.rs" autolib = false @@ -82,6 +82,10 @@ path = "tests/init.rs" name = "selfencrypt" path = "tests/selfencrypt.rs" +[dependencies.enum-map] +version = "2.7" +default-features = false + [dependencies.log] version = "0.4" default-features = false @@ -89,6 +93,11 @@ default-features = false [dependencies.neqo-common] path = "../neqo-common" +[dependencies.strum] +version = "0.26" +features = ["derive"] +default-features = false + [dev-dependencies.test-fixture] path = "../test-fixture" @@ -119,22 +128,56 @@ version = "0.5" default-features = false [lints.clippy] +allow_attributes = "warn" +allow_attributes_without_reason = "warn" cfg_not_test = "warn" clone_on_ref_ptr = "warn" create_dir = "warn" +dbg_macro = "warn" +empty_drop = "warn" +empty_enum_variants_with_brackets = "warn" +filetype_is_file = "warn" +float_cmp_const = "warn" +fn_to_numeric_cast_any = "warn" get_unwrap = "warn" if_then_some_else_none = "warn" +infinite_loop = "warn" +large_include_file = "warn" +let_underscore_must_use = "warn" +let_underscore_untyped = "warn" +literal_string_with_formatting_args = "allow" +lossy_float_literal = "warn" +mem_forget = "warn" +mixed_read_write_in_expression = "warn" +module_name_repetitions = "warn" multiple_crate_versions = "allow" multiple_inherent_impl = "warn" +mutex_atomic = "warn" +mutex_integer = "warn" +needless_raw_strings = "warn" pathbuf_init_then_push = "warn" +pub_without_shorthand = "warn" +rc_buffer = "warn" +rc_mutex = "warn" redundant_type_annotations = "warn" ref_patterns = "warn" renamed_function_params = "warn" +rest_pat_in_fully_bound_structs = "warn" +self_named_module_files = "warn" semicolon_inside_block = "warn" +string_lit_chars_any = "warn" +string_to_string = "warn" +suspicious_xor_used_as_pow = "warn" try_err = "warn" +unnecessary_safety_comment = "warn" +unnecessary_safety_doc = "warn" +unnecessary_self_imports = "warn" unneeded_field_pattern = "warn" unused_result_ok = "warn" unused_trait_names = "warn" +unwrap_in_result = "warn" +unwrap_used = "warn" +verbose_file_reads = "warn" [lints.clippy.cargo] level = "warn" @@ -151,7 +194,6 @@ priority = -1 [lints.rust] absolute_paths_not_starting_with_crate = "warn" ambiguous_negative_literals = "warn" -closure_returning_async_block = "warn" explicit_outlives_requirements = "warn" macro_use_extern_crate = "warn" missing_abi = "warn" @@ -163,3 +205,4 @@ unit_bindings = "warn" unused_import_braces = "warn" unused_lifetimes = "warn" unused_macro_rules = "warn" +unused_qualifications = "warn" diff --git a/third_party/rust/neqo-crypto/build.rs b/third_party/rust/neqo-crypto/build.rs index b61a8e92afed..3ef8ed7248a0 100644 --- a/third_party/rust/neqo-crypto/build.rs +++ b/third_party/rust/neqo-crypto/build.rs @@ -4,6 +4,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect(clippy::unwrap_used, reason = " OK in a build script.")] + use std::{ collections::HashMap, env, fs, @@ -54,13 +56,6 @@ struct Bindings { cplusplus: bool, } -fn is_debug() -> bool { - // Check the build profile and not whether debug symbols are enabled (i.e., - // `env::var("DEBUG")`), because we enable those for benchmarking/profiling and still want - // to build NSS in release mode. - env::var("PROFILE").unwrap_or_default() == "debug" -} - // bindgen needs access to libclang. // On windows, this doesn't just work, you have to set LIBCLANG_PATH. // Rather than download the 400Mb+ files, like gecko does, let's just reuse their work. @@ -136,21 +131,19 @@ fn build_nss(dir: PathBuf, nsstarget: &str) { } fn dynamic_link() { - let libs = if env::consts::OS == "windows" { - &["nssutil3.dll", "nss3.dll", "ssl3.dll"] + let dynamic_libs = if env::consts::OS == "windows" { + [ + "nssutil3.dll", + "nss3.dll", + "ssl3.dll", + "libplds4.dll", + "libplc4.dll", + "libnspr4.dll", + ] } else { - &["nssutil3", "nss3", "ssl3"] + ["nssutil3", "nss3", "ssl3", "plds4", "plc4", "nspr4"] }; - dynamic_link_both(libs); -} - -fn dynamic_link_both(extra_libs: &[&str]) { - let nspr_libs = if env::consts::OS == "windows" { - &["libplds4", "libplc4", "libnspr4"] - } else { - &["plds4", "plc4", "nspr4"] - }; - for lib in nspr_libs.iter().chain(extra_libs) { + for lib in dynamic_libs { println!("cargo:rustc-link-lib=dylib={lib}"); } } @@ -160,35 +153,71 @@ fn static_link() { "certdb", "certhi", "cryptohi", - "freebl", + "freebl_static", + if env::consts::OS == "windows" { + "libnspr4" + } else { + "nspr4" + }, "nss_static", "nssb", "nssdev", "nsspki", "nssutil", - "pk11wrap", - "pkcs12", - "pkcs7", - "smime", + "pk11wrap_static", + if env::consts::OS == "windows" { + "libplc4" + } else { + "plc4" + }, + if env::consts::OS == "windows" { + "libplds4" + } else { + "plds4" + }, "softokn_static", "ssl", ]; - if env::consts::OS != "macos" { + // macOS always dynamically links against the system sqlite library. + // See https://github.com/nss-dev/nss/blob/a8c22d8fc0458db3e261acc5e19b436ab573a961/coreconf/Darwin.mk#L130-L135 + if env::consts::OS == "macos" { + println!("cargo:rustc-link-lib=dylib=sqlite3"); + } else { static_libs.push("sqlite"); } + // Hardware specific libs. + // See https://github.com/mozilla/application-services/blob/0a2dac76f979b8bcfb6bacb5424b50f58520b8fe/components/support/rc_crypto/nss/nss_build_common/src/lib.rs#L127-L157 + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + // https://searchfox.org/nss/rev/0d5696b3edce5124353f03159d2aa15549db8306/lib/freebl/freebl.gyp#508-542 + if target_arch == "arm" || target_arch == "aarch64" { + static_libs.push("armv8_c_lib"); + } + if target_arch == "x86_64" || target_arch == "x86" { + static_libs.push("gcm-aes-x86_c_lib"); + static_libs.push("sha-x86_c_lib"); + } + if target_arch == "arm" { + static_libs.push("gcm-aes-arm32-neon_c_lib"); + } + if target_arch == "aarch64" { + static_libs.push("gcm-aes-aarch64_c_lib"); + } + if target_arch == "x86_64" { + static_libs.push("hw-acc-crypto-avx"); + static_libs.push("hw-acc-crypto-avx2"); + } + // https://searchfox.org/nss/rev/08c4d05078d00089f8d7540651b0717a9d66f87e/lib/freebl/freebl.gyp#315-324 + if (target_os == "android" || target_os == "linux") && target_arch == "x86_64" { + static_libs.push("intel-gcm-wrap_c_lib"); + // https://searchfox.org/nss/rev/08c4d05078d00089f8d7540651b0717a9d66f87e/lib/freebl/freebl.gyp#43-47 + if (target_os == "android" || target_os == "linux") && target_arch == "x86_64" { + static_libs.push("intel-gcm-s_lib"); + } + } for lib in static_libs { println!("cargo:rustc-link-lib=static={lib}"); } - - // Dynamic libs that aren't transitively included by NSS libs. - let mut other_libs = Vec::new(); - if env::consts::OS != "windows" { - other_libs.extend_from_slice(&["pthread", "dl", "c", "z"]); - } - if env::consts::OS == "macos" { - other_libs.push("sqlite3"); - } - dynamic_link_both(&other_libs); } fn get_includes(nsstarget: &Path, nssdist: &Path) -> Vec { @@ -336,7 +365,11 @@ fn setup_standalone(nss: &str) -> Vec { "cargo:rustc-link-search=native={}", nsslibdir.to_str().unwrap() ); - if is_debug() || env::consts::OS == "windows" { + if env::var("CARGO_CFG_FUZZING").is_ok() + || env::var("PROFILE").unwrap_or_default() == "debug" + // FIXME: NSPR doesn't build proper dynamic libraries on Windows. + || env::consts::OS == "windows" + { static_link(); } else { dynamic_link(); @@ -352,7 +385,10 @@ fn setup_standalone(nss: &str) -> Vec { #[cfg(feature = "gecko")] fn setup_for_gecko() -> Vec { - use mozbuild::TOPOBJDIR; + use mozbuild::{ + config::{BINDGEN_SYSTEM_FLAGS, NSPR_CFLAGS, NSS_CFLAGS}, + TOPOBJDIR, + }; let fold_libs = mozbuild::config::MOZ_FOLD_LIBS; let libs = if fold_libs { @@ -396,13 +432,11 @@ fn setup_for_gecko() -> Vec { ); } - let flags_path = TOPOBJDIR.join("netwerk/socket/neqo/extra-bindgen-flags"); - - println!("cargo:rerun-if-changed={}", flags_path.to_str().unwrap()); - let mut flags = fs::read_to_string(flags_path) - .expect("Failed to read extra-bindgen-flags file") - .split_whitespace() - .map(String::from) + let mut flags = BINDGEN_SYSTEM_FLAGS + .iter() + .chain(&NSPR_CFLAGS) + .chain(&NSS_CFLAGS) + .map(|s| s.to_string()) .collect::>(); flags.push(String::from("-include")); diff --git a/third_party/rust/neqo-crypto/min_version.txt b/third_party/rust/neqo-crypto/min_version.txt index d6d4e5562ce1..cf0e93ce7837 100644 --- a/third_party/rust/neqo-crypto/min_version.txt +++ b/third_party/rust/neqo-crypto/min_version.txt @@ -1 +1 @@ -3.105 +3.110 diff --git a/third_party/rust/neqo-crypto/src/aead.rs b/third_party/rust/neqo-crypto/src/aead.rs index 059e9acb6159..7fed060f752e 100644 --- a/third_party/rust/neqo-crypto/src/aead.rs +++ b/third_party/rust/neqo-crypto/src/aead.rs @@ -123,15 +123,46 @@ impl RealAead { c_uint::try_from(output.len())?, ) }?; - Ok(&output[0..(l.try_into()?)]) + Ok(&output[..l.try_into()?]) + } + + /// Encrypt `data` consisting of `aad` and plaintext `data` in place. + /// + /// The last `Aead::expansion` of `data` is overwritten by the AEAD tag by this function. + /// Therefore, a buffer should be provided that is that much larger than the plaintext. + /// + /// # Panics + /// + /// If `data` is shorter than `::expansion()`. + /// + /// # Errors + /// + /// If the input can't be protected or any input is too large for NSS. + pub fn encrypt_in_place<'a>( + &self, + count: u64, + aad: &[u8], + data: &'a mut [u8], + ) -> Res<&'a mut [u8]> { + let mut l: c_uint = 0; + unsafe { + SSL_AeadEncrypt( + *self.ctx, + count, + aad.as_ptr(), + c_uint::try_from(aad.len())?, + data.as_ptr(), + c_uint::try_from(data.len() - self.expansion())?, + data.as_ptr(), + &mut l, + c_uint::try_from(data.len())?, + ) + }?; + Ok(&mut data[..l.try_into()?]) } /// Decrypt a ciphertext. /// - /// Note that NSS insists upon having extra space available for decryption, so - /// the buffer for `output` should be the same length as `input`, even though - /// the final result will be shorter. - /// /// # Errors /// /// If the input isn't authenticated or any input is too large for NSS. @@ -144,6 +175,9 @@ impl RealAead { ) -> Res<&'a [u8]> { let mut l: c_uint = 0; unsafe { + // Note that NSS insists upon having extra space available for decryption, so + // the buffer for `output` should be the same length as `input`, even though + // the final result will be shorter. SSL_AeadDecrypt( *self.ctx, count, @@ -156,7 +190,41 @@ impl RealAead { c_uint::try_from(output.len())?, ) }?; - Ok(&output[0..(l.try_into()?)]) + Ok(&output[..l.try_into()?]) + } + + /// Decrypt a ciphertext in place. + /// Returns a subslice of `data` (without the last `::expansion()` bytes), + /// that has been decrypted in place. + /// + /// # Errors + /// + /// If the input isn't authenticated or any input is too large for NSS. + pub fn decrypt_in_place<'a>( + &self, + count: u64, + aad: &[u8], + data: &'a mut [u8], + ) -> Res<&'a mut [u8]> { + let mut l: c_uint = 0; + unsafe { + // Note that NSS insists upon having extra space available for decryption, so + // the buffer for `output` should be the same length as `input`, even though + // the final result will be shorter. + SSL_AeadDecrypt( + *self.ctx, + count, + aad.as_ptr(), + c_uint::try_from(aad.len())?, + data.as_ptr(), + c_uint::try_from(data.len())?, + data.as_ptr(), + &mut l, + c_uint::try_from(data.len())?, + ) + }?; + debug_assert_eq!(usize::try_from(l)?, data.len() - self.expansion()); + Ok(&mut data[..l.try_into()?]) } } diff --git a/third_party/rust/neqo-crypto/src/aead_null.rs b/third_party/rust/neqo-crypto/src/aead_null.rs index a74c89f35dbf..47caeda45aef 100644 --- a/third_party/rust/neqo-crypto/src/aead_null.rs +++ b/third_party/rust/neqo-crypto/src/aead_null.rs @@ -4,6 +4,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect(clippy::missing_errors_doc, reason = "OK here.")] + use std::fmt; use crate::{ @@ -17,7 +19,6 @@ pub const AEAD_NULL_TAG: &[u8] = &[0x0a; 16]; pub struct AeadNull {} impl AeadNull { - #[allow(clippy::missing_errors_doc)] pub const fn new( _version: Version, _cipher: Cipher, @@ -32,7 +33,6 @@ impl AeadNull { AEAD_NULL_TAG.len() } - #[allow(clippy::missing_errors_doc)] pub fn encrypt<'a>( &self, _count: u64, @@ -42,23 +42,30 @@ impl AeadNull { ) -> Res<&'a [u8]> { let l = input.len(); output[..l].copy_from_slice(input); - output[l..l + 16].copy_from_slice(AEAD_NULL_TAG); - Ok(&output[..l + 16]) + output[l..l + self.expansion()].copy_from_slice(AEAD_NULL_TAG); + Ok(&output[..l + self.expansion()]) } - #[allow(clippy::missing_errors_doc)] - pub fn decrypt<'a>( + pub fn encrypt_in_place<'a>( &self, _count: u64, _aad: &[u8], - input: &[u8], - output: &'a mut [u8], - ) -> Res<&'a [u8]> { - if input.len() < AEAD_NULL_TAG.len() { + data: &'a mut [u8], + ) -> Res<&'a mut [u8]> { + let pos = data.len() - self.expansion(); + data[pos..].copy_from_slice(AEAD_NULL_TAG); + Ok(data) + } + + fn decrypt_check(&self, _count: u64, _aad: &[u8], input: &[u8]) -> Res { + if input.len() < self.expansion() { return Err(Error::from(SEC_ERROR_BAD_DATA)); } - let len_encrypted = input.len() - AEAD_NULL_TAG.len(); + let len_encrypted = input + .len() + .checked_sub(self.expansion()) + .ok_or_else(|| Error::from(SEC_ERROR_BAD_DATA))?; // Check that: // 1) expansion is all zeros and // 2) if the encrypted data is also supplied that at least some values are no zero @@ -66,12 +73,34 @@ impl AeadNull { if &input[len_encrypted..] == AEAD_NULL_TAG && (len_encrypted == 0 || input[..len_encrypted].iter().any(|x| *x != 0x0)) { - output[..len_encrypted].copy_from_slice(&input[..len_encrypted]); - Ok(&output[..len_encrypted]) + Ok(len_encrypted) } else { Err(Error::from(SEC_ERROR_BAD_DATA)) } } + + pub fn decrypt<'a>( + &self, + count: u64, + aad: &[u8], + input: &[u8], + output: &'a mut [u8], + ) -> Res<&'a [u8]> { + self.decrypt_check(count, aad, input).map(|len| { + output[..len].copy_from_slice(&input[..len]); + &output[..len] + }) + } + + pub fn decrypt_in_place<'a>( + &self, + count: u64, + aad: &[u8], + data: &'a mut [u8], + ) -> Res<&'a mut [u8]> { + self.decrypt_check(count, aad, data) + .map(move |len| &mut data[..len]) + } } impl fmt::Debug for AeadNull { diff --git a/third_party/rust/neqo-crypto/src/agent.rs b/third_party/rust/neqo-crypto/src/agent.rs index 665efbf1a006..8b6291a0428b 100644 --- a/third_party/rust/neqo-crypto/src/agent.rs +++ b/third_party/rust/neqo-crypto/src/agent.rs @@ -4,6 +4,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow( + clippy::module_name_repetitions, + reason = "" +)] +#![expect( + clippy::unwrap_used, + reason = "Let's assume the use of `unwrap` was checked when the use of `unsafe` was reviewed." +)] + use std::{ cell::RefCell, ffi::{CStr, CString}, @@ -122,7 +131,11 @@ macro_rules! preinfo_arg { pub fn $v(&self) -> Option<$t> { match self.info.valuesSet & ssl::$m { 0 => None, - _ => Some(<$t>::try_from(self.info.$f).unwrap()), + _ => Some( + <$t>::try_from(self.info.$f) + .inspect_err(|e| qdebug!("Invalid value in preinfo: {e:?}")) + .ok()?, + ), } } }; @@ -135,7 +148,7 @@ impl SecretAgentPreInfo { ssl::SSL_GetPreliminaryChannelInfo( fd, info.as_mut_ptr(), - c_uint::try_from(std::mem::size_of::())?, + c_uint::try_from(size_of::())?, ) })?; @@ -158,12 +171,11 @@ impl SecretAgentPreInfo { self.info.canSendEarlyData != 0 } - /// # Panics + /// # Errors /// /// If `usize` is less than 32 bits and the value is too large. - #[must_use] - pub fn max_early_data(&self) -> usize { - usize::try_from(self.info.maxEarlyDataSize).unwrap() + pub fn max_early_data(&self) -> Res { + Ok(usize::try_from(self.info.maxEarlyDataSize)?) } /// Was ECH accepted. @@ -222,7 +234,7 @@ impl SecretAgentInfo { ssl::SSL_GetChannelInfo( fd, info.as_mut_ptr(), - c_uint::try_from(std::mem::size_of::())?, + c_uint::try_from(size_of::())?, ) })?; let info = unsafe { info.assume_init() }; @@ -273,7 +285,6 @@ impl SecretAgentInfo { /// `SecretAgent` holds the common parts of client and server. #[derive(Debug)] -#[allow(clippy::module_name_repetitions)] pub struct SecretAgent { fd: *mut ssl::PRFileDesc, secrets: SecretHolder, @@ -345,7 +356,6 @@ impl SecretAgent { Ok(fd) } - #[allow(clippy::missing_const_for_fn)] unsafe extern "C" fn auth_complete_hook( arg: *mut c_void, _fd: *mut ssl::PRFileDesc, @@ -544,9 +554,7 @@ impl SecretAgent { // NSS inherited an idiosyncratic API as a result of having implemented NPN // before ALPN. For that reason, we need to put the "best" option last. - let (first, rest) = protocols - .split_first() - .expect("at least one ALPN value needed"); + let (first, rest) = protocols.split_first().ok_or(Error::InternalError)?; for v in rest { add(v.as_ref()); } @@ -585,14 +593,16 @@ impl SecretAgent { // This function tracks whether handshake() or handshake_raw() was used // and prevents the other from being used. fn set_raw(&mut self, r: bool) -> Res<()> { - if self.raw.is_none() { + if let Some(raw) = self.raw { + if raw == r { + Ok(()) + } else { + Err(Error::MixedHandshakeMethod) + } + } else { self.secrets.register(self.fd)?; self.raw = Some(r); Ok(()) - } else if self.raw.unwrap() == r { - Ok(()) - } else { - Err(Error::MixedHandshakeMethod) } } @@ -627,6 +637,11 @@ impl SecretAgent { } /// Return any fatal alert that the TLS stack might have sent. + #[allow( + clippy::allow_attributes, + clippy::missing_const_for_fn, + reason = "TODO: False positive on nightly." + )] #[must_use] pub fn alert(&self) -> Option<&Alert> { (*self.alert).as_ref() @@ -751,12 +766,15 @@ impl SecretAgent { /// # Panics /// /// If setup fails. - #[allow(clippy::branches_sharing_code)] pub fn close(&mut self) { // It should be safe to close multiple times. if self.fd.is_null() { return; } + #[expect( + clippy::branches_sharing_code, + reason = "Moving the PR_Close call after the conditional crashes things?!" + )] if self.raw == Some(true) { // Need to hold the record list in scope until the close is done. let _records = self.setup_raw().expect("Can only close"); @@ -769,7 +787,7 @@ impl SecretAgent { unsafe { prio::PR_Close(self.fd.cast()); } - }; + } let _output = self.io.take_output(); self.fd = null_mut(); } @@ -793,6 +811,11 @@ impl SecretAgent { } /// Get the active ECH configuration, which is empty if ECH is disabled. + #[allow( + clippy::allow_attributes, + clippy::missing_const_for_fn, + reason = "TODO: False positive on nightly." + )] #[must_use] pub fn ech_config(&self) -> &[u8] { &self.ech_config @@ -840,13 +863,13 @@ impl ResumptionToken { /// A TLS Client. #[derive(Debug)] -#[allow(clippy::box_collection)] // We need the Box. pub struct Client { agent: SecretAgent, /// The name of the server we're attempting a connection to. server_name: String, /// Records the resumption tokens we've received. + #[expect(clippy::box_collection, reason = "We need the Box.")] resumption: Pin>>, } @@ -878,12 +901,10 @@ impl Client { arg: *mut c_void, ) -> ssl::SECStatus { let mut info: MaybeUninit = MaybeUninit::uninit(); - let info_res = &ssl::SSL_GetResumptionTokenInfo( - token, - len, - info.as_mut_ptr(), - c_uint::try_from(std::mem::size_of::()).unwrap(), - ); + let Ok(info_len) = c_uint::try_from(size_of::()) else { + return ssl::SECFailure; + }; + let info_res = &ssl::SSL_GetResumptionTokenInfo(token, len, info.as_mut_ptr(), info_len); if info_res.is_err() { // Ignore the token. return ssl::SECSuccess; @@ -893,8 +914,12 @@ impl Client { // Ignore the token. return ssl::SECSuccess; } - let resumption = arg.cast::>().as_mut().unwrap(); - let len = usize::try_from(len).unwrap(); + let Some(resumption) = arg.cast::>().as_mut() else { + return ssl::SECFailure; + }; + let Ok(len) = usize::try_from(len) else { + return ssl::SECFailure; + }; let mut v = Vec::with_capacity(len); v.extend_from_slice(null_safe_slice(token, len)); qdebug!("[{fd:p}] Got resumption token {}", hex_snip_middle(&v)); @@ -908,6 +933,11 @@ impl Client { ssl::SECSuccess } + #[allow( + clippy::allow_attributes, + clippy::missing_const_for_fn, + reason = "TODO: False positive on nightly." + )] #[must_use] pub fn server_name(&self) -> &str { &self.server_name @@ -985,7 +1015,6 @@ impl Client { impl Deref for Client { type Target = SecretAgent; - #[must_use] fn deref(&self) -> &SecretAgent { &self.agent } @@ -1194,7 +1223,6 @@ impl Server { impl Deref for Server { type Target = SecretAgent; - #[must_use] fn deref(&self) -> &SecretAgent { &self.agent } @@ -1221,7 +1249,6 @@ pub enum Agent { impl Deref for Agent { type Target = SecretAgent; - #[must_use] fn deref(&self) -> &SecretAgent { match self { Self::Client(c) => c, @@ -1240,14 +1267,12 @@ impl DerefMut for Agent { } impl From for Agent { - #[must_use] fn from(c: Client) -> Self { Self::Client(c) } } impl From for Agent { - #[must_use] fn from(s: Server) -> Self { Self::Server(s) } diff --git a/third_party/rust/neqo-crypto/src/agentio.rs b/third_party/rust/neqo-crypto/src/agentio.rs index 7bf14f941be6..0d38f3771dbc 100644 --- a/third_party/rust/neqo-crypto/src/agentio.rs +++ b/third_party/rust/neqo-crypto/src/agentio.rs @@ -4,6 +4,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect( + clippy::unwrap_used, + reason = "Let's assume the use of `unwrap` was checked when the use of `unsafe` was reviewed." +)] + use std::{ cmp::min, fmt, mem, @@ -95,10 +100,17 @@ impl RecordList { len: c_uint, arg: *mut c_void, ) -> ssl::SECStatus { - let records = arg.cast::().as_mut().unwrap(); - + let Ok(epoch) = Epoch::try_from(epoch) else { + return ssl::SECFailure; + }; + let Ok(ct) = ContentType::try_from(ct) else { + return ssl::SECFailure; + }; + let Some(records) = arg.cast::().as_mut() else { + return ssl::SECFailure; + }; let slice = null_safe_slice(data, len); - records.append(epoch, ContentType::try_from(ct).unwrap(), slice); + records.append(epoch, ct, slice); ssl::SECSuccess } @@ -114,7 +126,6 @@ impl RecordList { impl Deref for RecordList { type Target = Vec; - #[must_use] fn deref(&self) -> &Vec { &self.records } @@ -132,7 +143,6 @@ impl Iterator for RecordListIter { impl IntoIterator for RecordList { type Item = Record; type IntoIter = RecordListIter; - #[must_use] fn into_iter(self) -> Self::IntoIter { RecordListIter(self.records.into_iter()) } @@ -175,7 +185,10 @@ impl AgentIoInput { return Err(Error::NoDataAvailable); } - #[allow(clippy::disallowed_methods)] // We just checked if this was empty. + #[expect( + clippy::disallowed_methods, + reason = "We just checked if this was empty." + )] let src = unsafe { std::slice::from_raw_parts(self.input, amount) }; qtrace!("[{self}] read {}", hex(src)); let dst = unsafe { std::slice::from_raw_parts_mut(buf, amount) }; @@ -329,10 +342,14 @@ unsafe extern "C" fn agent_available64(mut fd: PrFd) -> prio::PRInt64 { .unwrap_or_else(|_| PR_FAILURE.into()) } -#[allow(clippy::cast_possible_truncation)] +#[expect( + clippy::cast_possible_truncation, + reason = "Cast is safe because prio::PR_AF_INET is 2." +)] unsafe extern "C" fn agent_getname(_fd: PrFd, addr: *mut prio::PRNetAddr) -> PrStatus { - let a = addr.as_mut().unwrap(); - // Cast is safe because prio::PR_AF_INET is 2 + let Some(a) = addr.as_mut() else { + return PR_FAILURE; + }; a.inet.family = prio::PR_AF_INET as prio::PRUint16; a.inet.port = 0; a.inet.ip = 0; @@ -340,10 +357,11 @@ unsafe extern "C" fn agent_getname(_fd: PrFd, addr: *mut prio::PRNetAddr) -> PrS } unsafe extern "C" fn agent_getsockopt(_fd: PrFd, opt: *mut prio::PRSocketOptionData) -> PrStatus { - let o = opt.as_mut().unwrap(); - if o.option == prio::PRSockOption::PR_SockOpt_Nonblocking { - o.value.non_blocking = 1; - return PR_SUCCESS; + if let Some(o) = opt.as_mut() { + if o.option == prio::PRSockOption::PR_SockOpt_Nonblocking { + o.value.non_blocking = 1; + return PR_SUCCESS; + } } PR_FAILURE } diff --git a/third_party/rust/neqo-crypto/src/auth.rs b/third_party/rust/neqo-crypto/src/auth.rs index 2932cdf2eb4e..a693ce27466d 100644 --- a/third_party/rust/neqo-crypto/src/auth.rs +++ b/third_party/rust/neqo-crypto/src/auth.rs @@ -4,105 +4,48 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use strum::FromRepr; + use crate::err::{mozpkix, sec, ssl, PRErrorCode}; /// The outcome of authentication. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, FromRepr)] +#[repr(i32)] pub enum AuthenticationStatus { Ok, - CaInvalid, - CaNotV3, - CertAlgorithmDisabled, - CertExpired, - CertInvalidTime, - CertIsCa, - CertKeyUsage, - CertMitm, - CertNotYetValid, - CertRevoked, - CertSelfSigned, - CertSubjectInvalid, - CertUntrusted, - CertWeakKey, - IssuerEmptyName, - IssuerExpired, - IssuerNotYetValid, - IssuerUnknown, - IssuerUntrusted, - PolicyRejection, - Unknown, + CaInvalid = sec::SEC_ERROR_CA_CERT_INVALID, + CaNotV3 = mozpkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA, + CertAlgorithmDisabled = sec::SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, + CertExpired = sec::SEC_ERROR_EXPIRED_CERTIFICATE, + CertInvalidTime = sec::SEC_ERROR_INVALID_TIME, + CertIsCa = mozpkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY, + CertKeyUsage = sec::SEC_ERROR_INADEQUATE_KEY_USAGE, + CertMitm = mozpkix::MOZILLA_PKIX_ERROR_MITM_DETECTED, + CertNotYetValid = mozpkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE, + CertRevoked = sec::SEC_ERROR_REVOKED_CERTIFICATE, + CertSelfSigned = mozpkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT, + CertSubjectInvalid = ssl::SSL_ERROR_BAD_CERT_DOMAIN, + CertUntrusted = sec::SEC_ERROR_UNTRUSTED_CERT, + CertWeakKey = mozpkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE, + IssuerEmptyName = mozpkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME, + IssuerExpired = sec::SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, + IssuerNotYetValid = mozpkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE, + IssuerUnknown = sec::SEC_ERROR_UNKNOWN_ISSUER, + IssuerUntrusted = sec::SEC_ERROR_UNTRUSTED_ISSUER, + PolicyRejection = mozpkix::MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED, + Unknown = sec::SEC_ERROR_LIBRARY_FAILURE, } impl From for PRErrorCode { - #[must_use] fn from(v: AuthenticationStatus) -> Self { - match v { - AuthenticationStatus::Ok => 0, - AuthenticationStatus::CaInvalid => sec::SEC_ERROR_CA_CERT_INVALID, - AuthenticationStatus::CaNotV3 => mozpkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA, - AuthenticationStatus::CertAlgorithmDisabled => { - sec::SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED - } - AuthenticationStatus::CertExpired => sec::SEC_ERROR_EXPIRED_CERTIFICATE, - AuthenticationStatus::CertInvalidTime => sec::SEC_ERROR_INVALID_TIME, - AuthenticationStatus::CertIsCa => { - mozpkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY - } - AuthenticationStatus::CertKeyUsage => sec::SEC_ERROR_INADEQUATE_KEY_USAGE, - AuthenticationStatus::CertMitm => mozpkix::MOZILLA_PKIX_ERROR_MITM_DETECTED, - AuthenticationStatus::CertNotYetValid => { - mozpkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE - } - AuthenticationStatus::CertRevoked => sec::SEC_ERROR_REVOKED_CERTIFICATE, - AuthenticationStatus::CertSelfSigned => mozpkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT, - AuthenticationStatus::CertSubjectInvalid => ssl::SSL_ERROR_BAD_CERT_DOMAIN, - AuthenticationStatus::CertUntrusted => sec::SEC_ERROR_UNTRUSTED_CERT, - AuthenticationStatus::CertWeakKey => mozpkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE, - AuthenticationStatus::IssuerEmptyName => mozpkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME, - AuthenticationStatus::IssuerExpired => sec::SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, - AuthenticationStatus::IssuerNotYetValid => { - mozpkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE - } - AuthenticationStatus::IssuerUnknown => sec::SEC_ERROR_UNKNOWN_ISSUER, - AuthenticationStatus::IssuerUntrusted => sec::SEC_ERROR_UNTRUSTED_ISSUER, - AuthenticationStatus::PolicyRejection => { - mozpkix::MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED - } - AuthenticationStatus::Unknown => sec::SEC_ERROR_LIBRARY_FAILURE, - } + v as Self } } // Note that this mapping should be removed after gecko eventually learns how to // map into the enumerated type. impl From for AuthenticationStatus { - #[must_use] fn from(v: PRErrorCode) -> Self { - match v { - 0 => Self::Ok, - sec::SEC_ERROR_CA_CERT_INVALID => Self::CaInvalid, - mozpkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA => Self::CaNotV3, - sec::SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED => Self::CertAlgorithmDisabled, - sec::SEC_ERROR_EXPIRED_CERTIFICATE => Self::CertExpired, - sec::SEC_ERROR_INVALID_TIME => Self::CertInvalidTime, - mozpkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY => Self::CertIsCa, - sec::SEC_ERROR_INADEQUATE_KEY_USAGE => Self::CertKeyUsage, - mozpkix::MOZILLA_PKIX_ERROR_MITM_DETECTED => Self::CertMitm, - mozpkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE => Self::CertNotYetValid, - sec::SEC_ERROR_REVOKED_CERTIFICATE => Self::CertRevoked, - mozpkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT => Self::CertSelfSigned, - ssl::SSL_ERROR_BAD_CERT_DOMAIN => Self::CertSubjectInvalid, - sec::SEC_ERROR_UNTRUSTED_CERT => Self::CertUntrusted, - mozpkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE => Self::CertWeakKey, - mozpkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME => Self::IssuerEmptyName, - sec::SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE => Self::IssuerExpired, - mozpkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE => Self::IssuerNotYetValid, - sec::SEC_ERROR_UNKNOWN_ISSUER => Self::IssuerUnknown, - sec::SEC_ERROR_UNTRUSTED_ISSUER => Self::IssuerUntrusted, - mozpkix::MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED => { - Self::PolicyRejection - } - _ => Self::Unknown, - } + Self::from_repr(v).unwrap_or(Self::Unknown) } } diff --git a/third_party/rust/neqo-crypto/src/constants.rs b/third_party/rust/neqo-crypto/src/constants.rs index 93228f8e14b1..abea78de4356 100644 --- a/third_party/rust/neqo-crypto/src/constants.rs +++ b/third_party/rust/neqo-crypto/src/constants.rs @@ -4,30 +4,49 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(dead_code)] +use enum_map::Enum; +use strum::FromRepr; -use crate::ssl; +use crate::{ssl, Error}; // Ideally all of these would be enums, but size matters and we need to allow // for values outside of those that are defined here. pub type Alert = u8; -pub type Epoch = u16; -// TLS doesn't really have an "initial" concept that maps to QUIC so directly, -// but this should be clear enough. -pub const TLS_EPOCH_INITIAL: Epoch = 0_u16; -pub const TLS_EPOCH_ZERO_RTT: Epoch = 1_u16; -pub const TLS_EPOCH_HANDSHAKE: Epoch = 2_u16; -// Also, we don't use TLS epochs > 3. -pub const TLS_EPOCH_APPLICATION_DATA: Epoch = 3_u16; +#[derive(Default, Debug, Enum, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromRepr)] +#[repr(u16)] +pub enum Epoch { + // TLS doesn't really have an "initial" concept that maps to QUIC so directly, + // but this should be clear enough. + #[default] + Initial = 0, + ZeroRtt, + Handshake, + ApplicationData, + // Also, we don't use TLS epochs > 3. +} + +impl TryFrom for Epoch { + type Error = Error; + + fn try_from(value: u16) -> Result { + Self::from_repr(value).ok_or(Error::InvalidEpoch) + } +} + +impl From for usize { + fn from(e: Epoch) -> Self { + e as Self + } +} /// Rather than defining a type alias and a bunch of constants, which leads to a ton of repetition, /// use this macro. macro_rules! remap_enum { { $t:ident: $s:ty { $( $n:ident = $v:path ),+ $(,)? } } => { pub type $t = $s; - $(#[allow(clippy::cast_possible_truncation)] pub const $n: $t = $v as $t; )+ + $(#[expect(clippy::cast_possible_truncation, reason = "Inherent in macro use.")] pub const $n: $t = $v as $t; )+ }; { $t:ident: $s:ty => $e:ident { $( $n:ident = $v:ident ),+ $(,)? } } => { remap_enum!{ $t: $s { $( $n = $e::$v ),+ } } @@ -44,6 +63,7 @@ remap_enum! { } } +#[expect(dead_code, reason = "Code is bindgen-generated.")] mod ciphers { include!(concat!(env!("OUT_DIR"), "/nss_ciphers.rs")); } diff --git a/third_party/rust/neqo-crypto/src/ech.rs b/third_party/rust/neqo-crypto/src/ech.rs index 29c4d2a37079..9e8a27493c6f 100644 --- a/third_party/rust/neqo-crypto/src/ech.rs +++ b/third_party/rust/neqo-crypto/src/ech.rs @@ -107,7 +107,7 @@ pub fn generate_keys() -> Res<(PrivateKey, PublicKey)> { params.extend_from_slice(oid_slc); let mut public_ptr: *mut SECKEYPublicKey = null_mut(); - let mut param_item = Item::wrap(¶ms); + let mut param_item = Item::wrap(¶ms)?; // If we have tracing on, try to ensure that key data can be read. let insensitive_secret_ptr = if log::log_enabled!(log::Level::Trace) { diff --git a/third_party/rust/neqo-crypto/src/err.rs b/third_party/rust/neqo-crypto/src/err.rs index 71ffc51953b0..1180e01d308e 100644 --- a/third_party/rust/neqo-crypto/src/err.rs +++ b/third_party/rust/neqo-crypto/src/err.rs @@ -4,29 +4,29 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(dead_code)] - use std::{os::raw::c_char, str::Utf8Error}; use crate::ssl::{SECStatus, SECSuccess}; include!(concat!(env!("OUT_DIR"), "/nspr_error.rs")); +#[expect(non_snake_case, dead_code, reason = "Code is bindgen-generated.")] mod codes { - #![allow(non_snake_case)] include!(concat!(env!("OUT_DIR"), "/nss_secerr.rs")); include!(concat!(env!("OUT_DIR"), "/nss_sslerr.rs")); } pub use codes::{SECErrorCodes as sec, SSLErrorCodes as ssl}; +#[expect(dead_code, reason = "Code is bindgen-generated.")] pub mod nspr { include!(concat!(env!("OUT_DIR"), "/nspr_err.rs")); } +#[expect(dead_code, reason = "Some constants are not used.")] pub mod mozpkix { // These are manually extracted from the many bindings generated // by bindgen when provided with the simple header: // #include "mozpkix/pkixnss.h" - #[allow(non_camel_case_types)] + #[expect(non_camel_case_types, reason = "Code is bindgen-generated.")] pub type mozilla_pkix_ErrorCode = ::std::os::raw::c_int; pub const MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE: mozilla_pkix_ErrorCode = -16384; pub const MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY: mozilla_pkix_ErrorCode = -16383; @@ -83,11 +83,9 @@ impl Error { } impl std::error::Error for Error { - #[must_use] fn cause(&self) -> Option<&dyn std::error::Error> { None } - #[must_use] fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } @@ -100,13 +98,11 @@ impl std::fmt::Display for Error { } impl From for Error { - #[must_use] fn from(_: std::num::TryFromIntError) -> Self { Self::IntegerOverflow } } impl From for Error { - #[must_use] fn from(_: std::ffi::NulError) -> Self { Self::InternalError } diff --git a/third_party/rust/neqo-crypto/src/exp.rs b/third_party/rust/neqo-crypto/src/exp.rs index c78343912812..6cded7c0ef99 100644 --- a/third_party/rust/neqo-crypto/src/exp.rs +++ b/third_party/rust/neqo-crypto/src/exp.rs @@ -7,10 +7,10 @@ #[macro_export] macro_rules! experimental_api { ( $n:ident ( $( $a:ident : $t:ty ),* $(,)? ) ) => { - #[allow(non_snake_case)] - #[allow(clippy::too_many_arguments)] - #[allow(clippy::missing_safety_doc)] - #[allow(clippy::missing_errors_doc)] + #[expect(non_snake_case, reason = "Inherent in macro use.")] + #[allow(clippy::allow_attributes, clippy::too_many_arguments, reason = "Inherent in macro use.")] + #[allow(clippy::allow_attributes, clippy::missing_safety_doc, reason = "Inherent in macro use.")] + #[allow(clippy::allow_attributes, clippy::missing_errors_doc, reason = "Inherent in macro use.")] pub unsafe fn $n ( $( $a : $t ),* ) -> Result<(), $crate::err::Error> { const EXP_FUNCTION: &str = stringify!($n); let n = ::std::ffi::CString::new(EXP_FUNCTION)?; diff --git a/third_party/rust/neqo-crypto/src/ext.rs b/third_party/rust/neqo-crypto/src/ext.rs index 02ee6340c12d..d9a8184bef1e 100644 --- a/third_party/rust/neqo-crypto/src/ext.rs +++ b/third_party/rust/neqo-crypto/src/ext.rs @@ -4,6 +4,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect( + clippy::unwrap_used, + reason = "Let's assume the use of `unwrap` was checked when the use of `unsafe` was reviewed." +)] + use std::{ cell::RefCell, os::raw::{c_uint, c_void}, @@ -75,7 +80,6 @@ impl ExtensionTracker { f(&mut *rc.borrow_mut()) } - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] unsafe extern "C" fn extension_writer( _fd: *mut PRFileDesc, message: SSLHandshakeType::Type, @@ -86,7 +90,12 @@ impl ExtensionTracker { ) -> PRBool { let d = std::slice::from_raw_parts_mut(data, max_len as usize); Self::wrap_handler_call(arg, |handler| { - // Cast is safe here because the message type is always part of the enum + #[allow( + clippy::allow_attributes, + clippy::cast_possible_truncation, + clippy::cast_sign_loss, + reason = "Cast is safe here because the message type is always part of the enum." + )] match handler.write(message as HandshakeMessage, d) { ExtensionWriterResult::Write(sz) => { *len = c_uint::try_from(sz).expect("integer overflow from extension writer"); @@ -106,9 +115,14 @@ impl ExtensionTracker { arg: *mut c_void, ) -> SECStatus { let d = null_safe_slice(data, len); - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] Self::wrap_handler_call(arg, |handler| { // Cast is safe here because the message type is always part of the enum + #[allow( + clippy::allow_attributes, + clippy::cast_possible_truncation, + clippy::cast_sign_loss, + reason = "Cast is safe here because the message type is always part of the enum." + )] match handler.handle(message as HandshakeMessage, d) { ExtensionHandlerResult::Ok => SECSuccess, ExtensionHandlerResult::Alert(a) => { diff --git a/third_party/rust/neqo-crypto/src/hkdf.rs b/third_party/rust/neqo-crypto/src/hkdf.rs index 2bdf40a4ff3a..0401692f3d1e 100644 --- a/third_party/rust/neqo-crypto/src/hkdf.rs +++ b/third_party/rust/neqo-crypto/src/hkdf.rs @@ -84,7 +84,7 @@ pub fn import_key(version: Version, buf: &[u8]) -> Res { CK_MECHANISM_TYPE::from(CKM_HKDF_DERIVE), PK11Origin::PK11_OriginUnwrap, CK_ATTRIBUTE_TYPE::from(CKA_DERIVE), - &mut Item::wrap(buf), + &mut Item::wrap(buf)?, null_mut(), ) }; diff --git a/third_party/rust/neqo-crypto/src/hp.rs b/third_party/rust/neqo-crypto/src/hp.rs index e8412b646efd..3b23aefdf0a9 100644 --- a/third_party/rust/neqo-crypto/src/hp.rs +++ b/third_party/rust/neqo-crypto/src/hp.rs @@ -4,6 +4,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow( + clippy::module_name_repetitions, + reason = "" +)] + use std::{ cell::RefCell, fmt::{self, Debug}, @@ -106,7 +111,7 @@ impl HpKey { mech, CK_ATTRIBUTE_TYPE::from(CKA_ENCRYPT), *key, - &Item::wrap(&ZERO[..0]), // Borrow a zero-length slice of ZERO. + &Item::wrap(&ZERO[..0])?, // Borrow a zero-length slice of ZERO. ) }; let context = Context::from_ptr(context_ptr).or(Err(Error::CipherInitFailure))?; @@ -169,7 +174,7 @@ impl HpKey { ulNonceBits: 96, }; let mut output_len: c_uint = 0; - let mut param_item = Item::wrap_struct(¶ms); + let mut param_item = Item::wrap_struct(¶ms)?; secstatus_to_res(unsafe { PK11_Encrypt( **key, diff --git a/third_party/rust/neqo-crypto/src/lib.rs b/third_party/rust/neqo-crypto/src/lib.rs index 44c24fcc8f6b..118b9adb044e 100644 --- a/third_party/rust/neqo-crypto/src/lib.rs +++ b/third_party/rust/neqo-crypto/src/lib.rs @@ -4,9 +4,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(clippy::module_name_repetitions)] // This lint doesn't work here. -#![allow(clippy::unseparated_literal_suffix, clippy::used_underscore_binding)] // For bindgen code. - mod aead; #[cfg(feature = "disable-encryption")] pub mod aead_null; @@ -31,7 +28,7 @@ pub mod selfencrypt; mod ssl; mod time; -use std::{ffi::CString, path::PathBuf, ptr::null, sync::OnceLock}; +use std::{env, ffi::CString, path::PathBuf, ptr::null, sync::OnceLock}; #[cfg(not(feature = "disable-encryption"))] pub use self::aead::RealAead as Aead; @@ -63,7 +60,7 @@ mod min_version; use min_version::MINIMUM_NSS_VERSION; use neqo_common::qerror; -#[allow(non_upper_case_globals)] +#[expect(non_upper_case_globals, reason = "Code is bindgen-generated.")] mod nss { include!(concat!(env!("OUT_DIR"), "/nss_init.rs")); } @@ -170,6 +167,9 @@ pub fn init() -> Res<()> { /// /// If NSS cannot be initialized. pub fn init_db>(dir: P) -> Res<()> { + // Allow overriding the NSS database path with an environment variable. + let dir = env::var("NSS_DB_PATH") + .unwrap_or(dir.into().to_str().ok_or(Error::InternalError)?.to_string()); let res = INITIALIZED.get_or_init(|| init_once(Some(dir.into()))); res.as_ref().map(|_| ()).map_err(Clone::clone) } @@ -201,7 +201,7 @@ where if data.is_null() || len == 0 { &[] } else { - #[allow(clippy::disallowed_methods)] + #[expect(clippy::disallowed_methods, reason = "This is non-null.")] std::slice::from_raw_parts(data, len) } } diff --git a/third_party/rust/neqo-crypto/src/p11.rs b/third_party/rust/neqo-crypto/src/p11.rs index 96d149ad829b..85bbf8664893 100644 --- a/third_party/rust/neqo-crypto/src/p11.rs +++ b/third_party/rust/neqo-crypto/src/p11.rs @@ -4,11 +4,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(dead_code)] -#![allow(non_upper_case_globals)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - use std::{ cell::RefCell, ops::{Deref, DerefMut}, @@ -24,7 +19,14 @@ use crate::{ null_safe_slice, }; -#[allow(clippy::unreadable_literal)] +#[expect( + dead_code, + non_snake_case, + non_upper_case_globals, + non_camel_case_types, + clippy::unreadable_literal, + reason = "For included bindgen code." +)] mod nss_p11 { include!(concat!(env!("OUT_DIR"), "/nss_p11.rs")); } @@ -44,6 +46,7 @@ macro_rules! scoped_ptr { /// # Errors /// /// When passed a null pointer generates an error. + #[allow(clippy::allow_attributes, dead_code, reason = "False positive.")] pub fn from_ptr(ptr: *mut $target) -> Result { if ptr.is_null() { Err($crate::err::Error::last_nss_error()) @@ -55,7 +58,6 @@ macro_rules! scoped_ptr { impl Deref for $scoped { type Target = *mut $target; - #[must_use] fn deref(&self) -> &*mut $target { &self.ptr } @@ -105,7 +107,6 @@ impl PublicKey { } impl Clone for PublicKey { - #[must_use] fn clone(&self) -> Self { let ptr = unsafe { SECKEY_CopyPublicKey(self.ptr) }; assert!(!ptr.is_null()); @@ -160,7 +161,6 @@ impl PrivateKey { unsafe impl Send for PrivateKey {} impl Clone for PrivateKey { - #[must_use] fn clone(&self) -> Self { let ptr = unsafe { SECKEY_CopyPrivateKey(self.ptr) }; assert!(!ptr.is_null()); @@ -208,7 +208,6 @@ impl SymKey { } impl Clone for SymKey { - #[must_use] fn clone(&self) -> Self { let ptr = unsafe { PK11_ReferenceSymKey(self.ptr) }; assert!(!ptr.is_null()); @@ -226,6 +225,12 @@ impl std::fmt::Debug for SymKey { } } +impl Default for SymKey { + fn default() -> Self { + Self { ptr: null_mut() } + } +} + unsafe fn destroy_pk11_context(ctxt: *mut PK11Context) { PK11_DestroyContext(ctxt, PRBool::from(true)); } @@ -247,25 +252,25 @@ impl Item { /// Creating this object is technically safe, but using it is extremely dangerous. /// Minimally, it can only be passed as a `const SECItem*` argument to functions, /// or those that treat their argument as `const`. - pub fn wrap(buf: &[u8]) -> SECItem { - SECItem { + pub fn wrap(buf: &[u8]) -> Res { + Ok(SECItem { type_: SECItemType::siBuffer, data: buf.as_ptr().cast_mut(), - len: c_uint::try_from(buf.len()).unwrap(), - } + len: c_uint::try_from(buf.len())?, + }) } /// Create a wrapper for a struct. /// Creating this object is technically safe, but using it is extremely dangerous. /// Minimally, it can only be passed as a `const SECItem*` argument to functions, /// or those that treat their argument as `const`. - pub fn wrap_struct(v: &T) -> SECItem { + pub fn wrap_struct(v: &T) -> Res { let data: *const T = v; - SECItem { + Ok(SECItem { type_: SECItemType::siBuffer, data: data.cast_mut().cast(), - len: c_uint::try_from(std::mem::size_of::()).unwrap(), - } + len: c_uint::try_from(size_of::())?, + }) } /// Make an empty `SECItem` for passing as a mutable `SECItem*` argument. @@ -276,20 +281,6 @@ impl Item { len: 0, } } - - /// This dereferences the pointer held by the item and makes a copy of the - /// content that is referenced there. - /// - /// # Safety - /// - /// This dereferences two pointers. It doesn't get much less safe. - pub unsafe fn into_vec(self) -> Vec { - let b = self.ptr.as_ref().unwrap(); - // Sanity check the type, as some types don't count bytes in `Item::len`. - assert_eq!(b.type_, SECItemType::siBuffer); - let slc = null_safe_slice(b.data, b.len); - Vec::from(slc) - } } unsafe fn destroy_secitem_array(array: *mut SECItemArray) { @@ -348,8 +339,8 @@ pub fn randomize>(mut buf: B) -> B { #[cfg(not(feature = "disable-random"))] pub fn randomize>(mut buf: B) -> B { let m_buf = buf.as_mut(); - let len = std::os::raw::c_int::try_from(m_buf.len()).unwrap(); - secstatus_to_res(unsafe { PK11_GenerateRandom(m_buf.as_mut_ptr(), len) }).unwrap(); + let len = std::os::raw::c_int::try_from(m_buf.len()).expect("usize fits into c_int"); + secstatus_to_res(unsafe { PK11_GenerateRandom(m_buf.as_mut_ptr(), len) }).expect("NSS failed"); buf } diff --git a/third_party/rust/neqo-crypto/src/prio.rs b/third_party/rust/neqo-crypto/src/prio.rs index fabea826e27b..bbbeaadf85b3 100644 --- a/third_party/rust/neqo-crypto/src/prio.rs +++ b/third_party/rust/neqo-crypto/src/prio.rs @@ -9,7 +9,9 @@ non_upper_case_globals, non_snake_case, clippy::cognitive_complexity, - clippy::too_many_lines + clippy::too_many_lines, + clippy::used_underscore_binding, + reason = "For included bindgen code." )] include!(concat!(env!("OUT_DIR"), "/nspr_io.rs")); diff --git a/third_party/rust/neqo-crypto/src/replay.rs b/third_party/rust/neqo-crypto/src/replay.rs index dcd5775f575f..d3ea02eea397 100644 --- a/third_party/rust/neqo-crypto/src/replay.rs +++ b/third_party/rust/neqo-crypto/src/replay.rs @@ -44,7 +44,6 @@ scoped_ptr!( /// It limits the exposure of servers to replay attack by rejecting 0-RTT /// if it appears to be a replay. There is a false-positive rate that can be /// managed by tuning the parameters used to create the context. -#[allow(clippy::module_name_repetitions)] pub struct AntiReplay { ctx: AntiReplayContext, } diff --git a/third_party/rust/neqo-crypto/src/secrets.rs b/third_party/rust/neqo-crypto/src/secrets.rs index 5d17d5fcdefa..82e75de9c7c1 100644 --- a/third_party/rust/neqo-crypto/src/secrets.rs +++ b/third_party/rust/neqo-crypto/src/secrets.rs @@ -4,9 +4,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{os::raw::c_void, pin::Pin}; +use std::{mem, os::raw::c_void, pin::Pin}; +use enum_map::EnumMap; use neqo_common::qdebug; +use strum::FromRepr; use crate::{ agentio::as_c_void, @@ -22,44 +24,37 @@ experimental_api!(SSL_SecretCallback( arg: *mut c_void, )); -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, FromRepr)] +#[cfg_attr(windows, repr(i32))] // Windows has to be different, of course. +#[cfg_attr(not(windows), repr(u32))] pub enum SecretDirection { - Read, - Write, + Read = SSLSecretDirection::ssl_secret_read, + Write = SSLSecretDirection::ssl_secret_write, } impl From for SecretDirection { - #[must_use] fn from(dir: SSLSecretDirection::Type) -> Self { - match dir { - SSLSecretDirection::ssl_secret_read => Self::Read, - SSLSecretDirection::ssl_secret_write => Self::Write, - _ => unreachable!(), - } + Self::from_repr(dir).expect("Invalid secret direction") } } #[derive(Debug, Default)] -#[allow(clippy::module_name_repetitions)] pub struct DirectionalSecrets { - // We only need to maintain 3 secrets for the epochs used during the handshake. - secrets: [Option; 3], + secrets: EnumMap, } impl DirectionalSecrets { fn put(&mut self, epoch: Epoch, key: SymKey) { - assert!(epoch > 0); - let i = (epoch - 1) as usize; - assert!(i < self.secrets.len()); - // assert!(self.secrets[i].is_none()); - self.secrets[i] = Some(key); + debug_assert!(epoch != Epoch::Initial); + self.secrets[epoch] = key; } pub fn take(&mut self, epoch: Epoch) -> Option { - assert!(epoch > 0); - let i = (epoch - 1) as usize; - assert!(i < self.secrets.len()); - self.secrets[i].take() + if self.secrets[epoch].is_null() { + None + } else { + Some(mem::take(&mut self.secrets[epoch])) + } } } @@ -77,7 +72,15 @@ impl Secrets { secret: *mut PK11SymKey, arg: *mut c_void, ) { - let secrets = arg.cast::().as_mut().unwrap(); + let Ok(epoch) = Epoch::try_from(epoch) else { + debug_assert!(false, "Invalid epoch"); + // Don't touch secrets. + return; + }; + let Some(secrets) = arg.cast::().as_mut() else { + debug_assert!(false, "No secrets"); + return; + }; secrets.put_raw(epoch, dir, secret); } diff --git a/third_party/rust/neqo-crypto/src/selfencrypt.rs b/third_party/rust/neqo-crypto/src/selfencrypt.rs index 7e5c6bb96424..6770c8e2e142 100644 --- a/third_party/rust/neqo-crypto/src/selfencrypt.rs +++ b/third_party/rust/neqo-crypto/src/selfencrypt.rs @@ -126,7 +126,7 @@ impl SelfEncrypt { /// /// Returns an error when the self-encrypted object is invalid; /// when the keys have been rotated; or when NSS fails. - #[allow(clippy::similar_names)] // aad is similar to aead + #[expect(clippy::similar_names, reason = "aad is similar to aead.")] pub fn open(&self, aad: &[u8], ciphertext: &[u8]) -> Res> { if ciphertext[0] != Self::VERSION { return Err(Error::SelfEncryptFailure); diff --git a/third_party/rust/neqo-crypto/src/ssl.rs b/third_party/rust/neqo-crypto/src/ssl.rs index 3dd2dbb8dd47..558986895f66 100644 --- a/third_party/rust/neqo-crypto/src/ssl.rs +++ b/third_party/rust/neqo-crypto/src/ssl.rs @@ -5,11 +5,13 @@ // except according to those terms. #![allow( + clippy::allow_attributes, dead_code, non_upper_case_globals, non_snake_case, + clippy::cognitive_complexity, clippy::too_many_lines, - clippy::cognitive_complexity + reason = "For included bindgen code." )] use std::os::raw::{c_uint, c_void}; @@ -20,56 +22,41 @@ use crate::{ }; include!(concat!(env!("OUT_DIR"), "/nss_ssl.rs")); +#[expect(non_snake_case, reason = "OK here.")] mod SSLOption { include!(concat!(env!("OUT_DIR"), "/nss_sslopt.rs")); } -// I clearly don't understand how bindgen operates. -pub enum PLArenaPool {} pub enum PRFileDesc {} // Remap some constants. +#[expect(non_upper_case_globals, reason = "OK here.")] pub const SECSuccess: SECStatus = _SECStatus_SECSuccess; +#[expect(non_upper_case_globals, reason = "OK here.")] pub const SECFailure: SECStatus = _SECStatus_SECFailure; #[derive(Debug, Copy, Clone)] +#[repr(u32)] pub enum Opt { - Locking, - Tickets, - OcspStapling, - Alpn, - ExtendedMasterSecret, - SignedCertificateTimestamps, - EarlyData, - RecordSizeLimit, - Tls13CompatMode, - HelloDowngradeCheck, - SuppressEndOfEarlyData, - Grease, - EnableChExtensionPermutation, + Locking = SSLOption::SSL_NO_LOCKS, + Tickets = SSLOption::SSL_ENABLE_SESSION_TICKETS, + OcspStapling = SSLOption::SSL_ENABLE_OCSP_STAPLING, + Alpn = SSLOption::SSL_ENABLE_ALPN, + ExtendedMasterSecret = SSLOption::SSL_ENABLE_EXTENDED_MASTER_SECRET, + SignedCertificateTimestamps = SSLOption::SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, + EarlyData = SSLOption::SSL_ENABLE_0RTT_DATA, + RecordSizeLimit = SSLOption::SSL_RECORD_SIZE_LIMIT, + Tls13CompatMode = SSLOption::SSL_ENABLE_TLS13_COMPAT_MODE, + HelloDowngradeCheck = SSLOption::SSL_ENABLE_HELLO_DOWNGRADE_CHECK, + SuppressEndOfEarlyData = SSLOption::SSL_SUPPRESS_END_OF_EARLY_DATA, + Grease = SSLOption::SSL_ENABLE_GREASE, + EnableChExtensionPermutation = SSLOption::SSL_ENABLE_CH_EXTENSION_PERMUTATION, } impl Opt { - // Cast is safe here because SSLOptions are within the i32 range - #[allow(clippy::cast_possible_wrap)] #[must_use] pub const fn as_int(self) -> PRInt32 { - let i = match self { - Self::Locking => SSLOption::SSL_NO_LOCKS, - Self::Tickets => SSLOption::SSL_ENABLE_SESSION_TICKETS, - Self::OcspStapling => SSLOption::SSL_ENABLE_OCSP_STAPLING, - Self::Alpn => SSLOption::SSL_ENABLE_ALPN, - Self::ExtendedMasterSecret => SSLOption::SSL_ENABLE_EXTENDED_MASTER_SECRET, - Self::SignedCertificateTimestamps => SSLOption::SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, - Self::EarlyData => SSLOption::SSL_ENABLE_0RTT_DATA, - Self::RecordSizeLimit => SSLOption::SSL_RECORD_SIZE_LIMIT, - Self::Tls13CompatMode => SSLOption::SSL_ENABLE_TLS13_COMPAT_MODE, - Self::HelloDowngradeCheck => SSLOption::SSL_ENABLE_HELLO_DOWNGRADE_CHECK, - Self::SuppressEndOfEarlyData => SSLOption::SSL_SUPPRESS_END_OF_EARLY_DATA, - Self::Grease => SSLOption::SSL_ENABLE_GREASE, - Self::EnableChExtensionPermutation => SSLOption::SSL_ENABLE_CH_EXTENSION_PERMUTATION, - }; - i as PRInt32 + self as PRInt32 } // Some options are backwards, like SSL_NO_LOCKS, so use this to manage that. @@ -86,11 +73,6 @@ impl Opt { } } -experimental_api!(SSL_GetCurrentEpoch( - fd: *mut PRFileDesc, - read_epoch: *mut u16, - write_epoch: *mut u16, -)); experimental_api!(SSL_HelloRetryRequestCallback( fd: *mut PRFileDesc, cb: SSLHelloRetryRequestCallback, diff --git a/third_party/rust/neqo-crypto/src/time.rs b/third_party/rust/neqo-crypto/src/time.rs index 5375833df9bd..3413d38809e9 100644 --- a/third_party/rust/neqo-crypto/src/time.rs +++ b/third_party/rust/neqo-crypto/src/time.rs @@ -4,6 +4,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![expect( + clippy::unwrap_used, + reason = "Let's assume the use of `unwrap` was checked when the use of `unsafe` was reviewed." +)] + use std::{ ops::Deref, os::raw::c_void, @@ -139,7 +144,6 @@ impl TryInto for Time { } impl From