Backed out 2 changesets (bug 1772092) for causing build bustages. CLOSED TREE

Backed out changeset 30a2c0f4c97f (bug 1772092)
Backed out changeset 7dd164e9428c (bug 1772092)
This commit is contained in:
criss 2022-06-09 13:29:59 +03:00
parent cebccb13b0
commit 44a8e72bfb
92 changed files with 987 additions and 3197 deletions

View File

@ -15,7 +15,7 @@ rev = "75ada456c92a429704691a85e1cb42fef8cafc0d"
[source."https://github.com/mozilla/neqo"]
git = "https://github.com/mozilla/neqo"
replace-with = "vendored-sources"
tag = "v0.6.0"
tag = "v0.5.7"
[source."https://github.com/mozilla/mp4parse-rust"]
git = "https://github.com/mozilla/mp4parse-rust"

45
Cargo.lock generated
View File

@ -382,7 +382,7 @@ version = "1.1.0"
name = "baldrdash"
version = "0.1.0"
dependencies = [
"bindgen",
"bindgen 0.59.2",
"cranelift-codegen",
"cranelift-wasm",
"env_logger 0.8.999",
@ -420,6 +420,13 @@ dependencies = [
"serde",
]
[[package]]
name = "bindgen"
version = "0.56.999"
dependencies = [
"bindgen 0.59.2",
]
[[package]]
name = "bindgen"
version = "0.59.2"
@ -903,7 +910,7 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dff444d80630d7073077d38d40b4501fd518bd2b922c2a55edcc8b0f7be57e6"
dependencies = [
"bindgen",
"bindgen 0.59.2",
]
[[package]]
@ -2017,7 +2024,7 @@ name = "gecko-profiler"
version = "0.1.0"
dependencies = [
"bincode",
"bindgen",
"bindgen 0.59.2",
"lazy_static",
"mozbuild",
"profiler-macros",
@ -2527,7 +2534,7 @@ name = "http3server"
version = "0.1.1"
dependencies = [
"base64",
"bindgen",
"bindgen 0.59.2",
"log",
"mio 0.6.23",
"mio-extras",
@ -3090,9 +3097,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.17"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if 1.0.0",
]
@ -3458,7 +3465,7 @@ dependencies = [
name = "mozilla-central-workspace-hack"
version = "0.1.0"
dependencies = [
"bindgen",
"bindgen 0.59.2",
"libc",
"quote",
"serde",
@ -3577,8 +3584,8 @@ dependencies = [
[[package]]
name = "neqo-common"
version = "0.6.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.6.0#c9c013390ba68b401b5205c134e69d8898c2f299"
version = "0.5.7"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.7#f3de275b12c40f45718ce43a0482e771ba6cd4b8"
dependencies = [
"chrono",
"env_logger 0.8.999",
@ -3590,10 +3597,10 @@ dependencies = [
[[package]]
name = "neqo-crypto"
version = "0.6.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.6.0#c9c013390ba68b401b5205c134e69d8898c2f299"
version = "0.5.7"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.7#f3de275b12c40f45718ce43a0482e771ba6cd4b8"
dependencies = [
"bindgen",
"bindgen 0.56.999",
"log",
"mozbuild",
"neqo-common",
@ -3604,8 +3611,8 @@ dependencies = [
[[package]]
name = "neqo-http3"
version = "0.6.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.6.0#c9c013390ba68b401b5205c134e69d8898c2f299"
version = "0.5.7"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.7#f3de275b12c40f45718ce43a0482e771ba6cd4b8"
dependencies = [
"enumset",
"lazy_static",
@ -3622,8 +3629,8 @@ dependencies = [
[[package]]
name = "neqo-qpack"
version = "0.6.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.6.0#c9c013390ba68b401b5205c134e69d8898c2f299"
version = "0.5.7"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.7#f3de275b12c40f45718ce43a0482e771ba6cd4b8"
dependencies = [
"lazy_static",
"log",
@ -3636,8 +3643,8 @@ dependencies = [
[[package]]
name = "neqo-transport"
version = "0.6.0"
source = "git+https://github.com/mozilla/neqo?tag=v0.6.0#c9c013390ba68b401b5205c134e69d8898c2f299"
version = "0.5.7"
source = "git+https://github.com/mozilla/neqo?tag=v0.5.7#f3de275b12c40f45718ce43a0482e771ba6cd4b8"
dependencies = [
"indexmap",
"lazy_static",
@ -4987,7 +4994,7 @@ dependencies = [
"app_units",
"arrayvec",
"atomic_refcell",
"bindgen",
"bindgen 0.59.2",
"bitflags",
"byteorder",
"cssparser",

View File

@ -94,6 +94,9 @@ mozbuild = { path = "build/rust/mozbuild" }
# Patch itoa 0.4 to 1.0.
itoa = { path = "build/rust/itoa" }
# Patch bindgen 0.56 to 0.59.
bindgen = { path = "build/rust/bindgen" }
# Patch cfg-if 0.1 to 1.0
cfg-if = { path = "build/rust/cfg-if" }

View File

@ -0,0 +1,19 @@
[package]
name = "bindgen"
version = "0.56.999"
edition = "2018"
license = "BSD-3-Clause"
[lib]
path = "lib.rs"
[dependencies.bindgen]
version = "0.59"
default-features = false
[features]
default = ["bindgen/default"]
logging = ["bindgen/logging"]
runtime = ["bindgen/runtime"]
static = ["bindgen/static"]
which-rustfmt = ["bindgen/which-rustfmt"]

26
build/rust/bindgen/lib.rs Normal file
View File

@ -0,0 +1,26 @@
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pub use bindgen::*;

View File

@ -8,10 +8,10 @@ edition = "2018"
name = "neqo_glue"
[dependencies]
neqo-http3 = { tag = "v0.6.0", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.6.0", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.6.0", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.6.0", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.5.7", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.5.7", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.5.7", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.5.7", git = "https://github.com/mozilla/neqo" }
nserror = { path = "../../../xpcom/rust/nserror" }
nsstring = { path = "../../../xpcom/rust/nsstring" }
xpcom = { path = "../../../xpcom/rust/xpcom" }
@ -25,7 +25,7 @@ static_prefs = { path = "../../../modules/libpref/init/static_prefs", optional =
winapi = {version = "0.3", features = ["ws2def"] }
[dependencies.neqo-crypto]
tag = "v0.6.0"
tag = "v0.5.7"
git = "https://github.com/mozilla/neqo"
default-features = false
features = ["gecko"]

View File

@ -11,7 +11,7 @@ use neqo_http3::{Error as Http3Error, Priority};
use neqo_http3::{Http3Client, Http3ClientEvent, Http3Parameters, Http3State};
use neqo_transport::{
stream_id::StreamType, CongestionControlAlgorithm, ConnectionParameters,
Error as TransportError, Output, Version, RandomConnectionIdGenerator, StreamId,
Error as TransportError, Output, QuicVersion, RandomConnectionIdGenerator, StreamId,
};
use nserror::*;
use nsstring::*;
@ -106,17 +106,17 @@ impl NeqoHttp3Conn {
let remote: SocketAddr = netaddr_to_socket_addr(remote_addr)?;
let quic_version = match alpn_conv {
"h3-32" => Version::Draft32,
"h3-31" => Version::Draft31,
"h3-30" => Version::Draft30,
"h3-29" => Version::Draft29,
"h3" => Version::Version1,
"h3-32" => QuicVersion::Draft32,
"h3-31" => QuicVersion::Draft31,
"h3-30" => QuicVersion::Draft30,
"h3-29" => QuicVersion::Draft29,
"h3" => QuicVersion::Version1,
_ => return Err(NS_ERROR_INVALID_ARG),
};
#[allow(unused_mut)]
let mut params = ConnectionParameters::default()
.versions(quic_version, vec![quic_version])
.quic_version(quic_version)
.cc_algorithm(CongestionControlAlgorithm::Cubic)
.max_data(max_data)
.max_stream_data(StreamType::BiDi, false, max_stream_data);
@ -461,6 +461,7 @@ pub extern "C" fn neqo_htttp3conn_send_request_body(
fn crypto_error_code(err: neqo_crypto::Error) -> u64 {
match err {
neqo_crypto::Error::AeadInitFailure => 0,
neqo_crypto::Error::AeadError => 1,
neqo_crypto::Error::CertificateLoading => 2,
neqo_crypto::Error::CreateSslSocket => 3,
@ -478,7 +479,6 @@ fn crypto_error_code(err: neqo_crypto::Error) -> u64 {
neqo_crypto::Error::UnsupportedVersion => 15,
neqo_crypto::Error::StringError => 16,
neqo_crypto::Error::EchRetry(_) => 17,
neqo_crypto::Error::CipherInitFailure => 18,
}
}
@ -536,7 +536,7 @@ impl From<TransportError> for CloseError {
TransportError::InvalidResumptionToken => CloseError::TransportInternalErrorOther(11),
TransportError::InvalidRetry => CloseError::TransportInternalErrorOther(12),
TransportError::InvalidStreamId => CloseError::TransportInternalErrorOther(13),
TransportError::KeysDiscarded(_) => CloseError::TransportInternalErrorOther(14),
TransportError::KeysDiscarded => CloseError::TransportInternalErrorOther(14),
TransportError::KeysPending(_) => CloseError::TransportInternalErrorOther(15),
TransportError::KeyUpdateBlocked => CloseError::TransportInternalErrorOther(16),
TransportError::NoMoreData => CloseError::TransportInternalErrorOther(17),
@ -551,7 +551,6 @@ impl From<TransportError> for CloseError {
TransportError::WrongRole => CloseError::TransportInternalErrorOther(26),
TransportError::QlogError => CloseError::TransportInternalErrorOther(27),
TransportError::NotAvailable => CloseError::TransportInternalErrorOther(28),
TransportError::DisabledVersion => CloseError::TransportInternalErrorOther(29),
}
}
}

View File

@ -5,17 +5,17 @@ authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
edition = "2018"
[dependencies]
neqo-transport = { tag = "v0.6.0", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.6.0", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.6.0", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.6.0", git = "https://github.com/mozilla/neqo" }
neqo-transport = { tag = "v0.5.7", git = "https://github.com/mozilla/neqo" }
neqo-common = { tag = "v0.5.7", git = "https://github.com/mozilla/neqo" }
neqo-http3 = { tag = "v0.5.7", git = "https://github.com/mozilla/neqo" }
neqo-qpack = { tag = "v0.5.7", git = "https://github.com/mozilla/neqo" }
mio = "0.6.17"
mio-extras = "2.0.5"
log = "0.4.0"
base64 = "0.13"
[dependencies.neqo-crypto]
tag = "v0.6.0"
tag = "v0.5.7"
git = "https://github.com/mozilla/neqo"
default-features = false
features = ["gecko"]

View File

@ -882,7 +882,7 @@ version = "0.4.5"
criteria = "safe-to-deploy"
[[unaudited.log]]
version = "0.4.17"
version = "0.4.14"
criteria = "safe-to-deploy"
[[unaudited.mach]]

View File

@ -1 +1 @@
{"files":{"CHANGELOG.md":"d96bb13d82aab1b8f01a077167eb3968fe27c4fbb7aa4933f0e257d42794eb76","Cargo.toml":"e0ff3b07a36ad23348c9cc7113ad787aefbc0c7b75517f5a68247863a4994e1c","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"705aaaaecefa087c187bd2eacdb01b8ac1c5ee95b1d5d04d8d7efe0363207df8","README.md":"bd6ed9b3c1cf3329d7afca04eb03f5c36e75cf9cb0bbbffddb7f07f3f36f2ea0","benches/value.rs":"55bd5f795a524f0699b2858eb14cc456abebeb43d50c90d2bfc77cd7856e8050","build.rs":"91dd121dd1aa749c8c0c24bda658309d1313baa022afbc5af1fabd1104622376","src/kv/error.rs":"01d37bb1ecbb2ba1145cd6df0b0b9a3ea3f1a2c9586a4908d3256cb865365b7e","src/kv/key.rs":"e74b489cde28960f76d4038b02867b4cb724c206d31abd461abeaa04e73cf7ef","src/kv/mod.rs":"9d916f43fd9c2829991fcff6db32f23bb7864e1113a622d49e59f110e2f290cf","src/kv/source.rs":"3f7aadc5f30c0c821fd20d899d8529eba8088eeda0c8603814de689da25dd4e8","src/kv/value.rs":"3387875f0ffd5f4747f181c3bc5134974358993981e54b1f203d6dd835a50245","src/lib.rs":"69dd3c57d9c6438d2e5bda9dc657827dcd73561faff708358f2e6854f47a2a3d","src/macros.rs":"642640f48a9d61efed0213b3a61a2864e80e8f8ffb9541b7c44d3028d3a7f08c","src/serde.rs":"d8190561ed64398fe45142b261000255ea1bcda8707e6f1b07ef4b805da6829b","triagebot.toml":"2d1d46d069bc4e3739069676707ca2801e0e0ba58a784a264392362ff9ac4a77"},"package":"abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"}
{"files":{"CHANGELOG.md":"5fa3f03a8dfa3934f5b1cfba9a41781700ed6e67afe0f10717cc16b6855ceb16","Cargo.toml":"2863cdd3382ede73ecc608ad22a4d8ee476abed3b0016f9724deba59e9317338","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"705aaaaecefa087c187bd2eacdb01b8ac1c5ee95b1d5d04d8d7efe0363207df8","README.md":"ca758a44f4a226f21b3bc997d27a5356b5e77ee13a1daad24ee8bbbebb301c5d","benches/value.rs":"55bd5f795a524f0699b2858eb14cc456abebeb43d50c90d2bfc77cd7856e8050","build.rs":"2bfb7564209da7c4d10433d9639d33541a89d63fc52cbe47d479a967cf746769","src/kv/error.rs":"ba46a4bcac717e6dc58fc5101833c825d7b95777c1dd907be46c8fa573a27d2d","src/kv/key.rs":"e74b489cde28960f76d4038b02867b4cb724c206d31abd461abeaa04e73cf7ef","src/kv/mod.rs":"9d916f43fd9c2829991fcff6db32f23bb7864e1113a622d49e59f110e2f290cf","src/kv/source.rs":"3f7aadc5f30c0c821fd20d899d8529eba8088eeda0c8603814de689da25dd4e8","src/kv/value.rs":"4d46ced0adbe385701c1d80d03c0f2abde2e43acf16521a9d26f058462f43799","src/lib.rs":"320a18401e7f9edc812a52b5be029fb9ef8c6d7435ab7b52650878477d21103b","src/macros.rs":"b0174b17f5e06b6a7bafb7873c79c7f8e2c70a531686adf03c027739ee040a44","src/serde.rs":"d8190561ed64398fe45142b261000255ea1bcda8707e6f1b07ef4b805da6829b","triagebot.toml":"2d1d46d069bc4e3739069676707ca2801e0e0ba58a784a264392362ff9ac4a77"},"package":"51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"}

View File

@ -2,29 +2,6 @@
## [Unreleased]
## [0.4.17] - 2022-04-29
* Update `kv_unstable` internal dependencies.
## [0.4.16] - 2022-03-22
* Fix a conflict with unqualified `Option` use in macros.
## [0.4.15] - 2022-02-23
* Silence a warning about the deprecated `spin_loop_hint`.
* Relax ordering in the atomic `set_max_level` call.
* Add thumbv4t-none-eabi to targets that don't support atomics
* Allow levels to be iterated over.
* Implement `Log` on some common wrapper types.
* Improvements to test coverage.
* Improvements to documentation.
* Add key-value support to the `log!` macros.
* Tighten `kv_unstable` internal dependencies so they don't bump past their current alpha.
* Add a simple visit API to `kv_unstable`.
* Support `NonZero*` integers as values in structured logging
* Support static strings as keys in structured logging
## [0.4.14] - 2021-01-27
* Remove the `__private_api_log_lit` special case.
@ -219,10 +196,7 @@ version using log 0.4.x to avoid losing module and file information.
Look at the [release tags] for information about older releases.
[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.17...HEAD
[0.4.17]: https://github.com/rust-lang-nursery/log/compare/0.4.16...0.4.17
[0.4.16]: https://github.com/rust-lang-nursery/log/compare/0.4.15...0.4.16
[0.4.15]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.15
[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.14...HEAD
[0.4.14]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.14
[0.4.13]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.13
[0.4.12]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.12

View File

@ -3,36 +3,28 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
# to registry (e.g., crates.io) dependencies
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "log"
version = "0.4.17"
version = "0.4.14"
authors = ["The Rust Project Developers"]
build = "build.rs"
exclude = ["rfcs/**/*"]
description = """
A lightweight logging facade for Rust
"""
exclude = ["rfcs/**/*", "/.travis.yml", "/appveyor.yml"]
description = "A lightweight logging facade for Rust\n"
documentation = "https://docs.rs/log"
readme = "README.md"
keywords = ["logging"]
categories = ["development-tools::debugging"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/log"
[package.metadata.docs.rs]
features = [
"std",
"serde",
"kv_unstable_std",
"kv_unstable_sval",
"kv_unstable_serde",
]
features = ["std", "serde", "kv_unstable_std", "kv_unstable_sval", "kv_unstable_serde"]
[[test]]
name = "filters"
@ -43,7 +35,6 @@ harness = false
name = "macros"
path = "tests/macros.rs"
harness = true
[dependencies.cfg-if]
version = "1.0"
@ -53,18 +44,14 @@ optional = true
default-features = false
[dependencies.sval]
version = "=1.0.0-alpha.5"
version = "1.0.0-alpha.5"
optional = true
default-features = false
[dependencies.value-bag]
version = "=1.0.0-alpha.9"
version = "1.0.0-alpha.6"
optional = true
default-features = false
[dev-dependencies.rustversion]
version = "1.0"
[dev-dependencies.serde]
version = "1.0"
features = ["derive"]
@ -73,30 +60,18 @@ features = ["derive"]
version = "1.0"
[dev-dependencies.sval]
version = "=1.0.0-alpha.5"
version = "1.0.0-alpha.5"
features = ["derive"]
[dev-dependencies.value-bag]
version = "=1.0.0-alpha.9"
version = "1.0.0-alpha.6"
features = ["test"]
[features]
kv_unstable = ["value-bag"]
kv_unstable_serde = [
"kv_unstable_std",
"value-bag/serde",
"serde",
]
kv_unstable_std = [
"std",
"kv_unstable",
"value-bag/error",
]
kv_unstable_sval = [
"kv_unstable",
"value-bag/sval",
"sval",
]
kv_unstable_serde = ["kv_unstable_std", "value-bag/serde", "serde"]
kv_unstable_std = ["std", "kv_unstable", "value-bag/error"]
kv_unstable_sval = ["kv_unstable", "value-bag/sval", "sval"]
max_level_debug = []
max_level_error = []
max_level_info = []

View File

@ -24,7 +24,7 @@ This version is explicitly tested in CI and may be bumped in any release as need
## Usage
### In libraries
## In libraries
Libraries should link only to the `log` crate, and use the provided macros to
log whatever information will be useful to downstream consumers:
@ -55,15 +55,15 @@ pub fn shave_the_yak(yak: &mut Yak) {
}
```
### In executables
## In executables
In order to produce log output, executables have to use a logger implementation compatible with the facade.
There are many available implementations to choose from, here are some of the most popular ones:
* Simple minimal loggers:
* [`env_logger`](https://docs.rs/env_logger/*/env_logger/)
* [`simple_logger`](https://docs.rs/simple_logger/*/simple_logger/)
* [`simplelog`](https://docs.rs/simplelog/*/simplelog/)
* [`simple_logger`](https://github.com/borntyping/rust-simple_logger)
* [`simplelog`](https://github.com/drakulix/simplelog.rs)
* [`pretty_env_logger`](https://docs.rs/pretty_env_logger/*/pretty_env_logger/)
* [`stderrlog`](https://docs.rs/stderrlog/*/stderrlog/)
* [`flexi_logger`](https://docs.rs/flexi_logger/*/flexi_logger/)
@ -72,17 +72,11 @@ There are many available implementations to choose from, here are some of the mo
* [`fern`](https://docs.rs/fern/*/fern/)
* Adaptors for other facilities:
* [`syslog`](https://docs.rs/syslog/*/syslog/)
* [`systemd-journal-logger`](https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/)
* [`slog-stdlog`](https://docs.rs/slog-stdlog/*/slog_stdlog/)
* [`android_log`](https://docs.rs/android_log/*/android_log/)
* [`win_dbg_logger`](https://docs.rs/win_dbg_logger/*/win_dbg_logger/)
* [`db_logger`](https://docs.rs/db_logger/*/db_logger/)
* For WebAssembly binaries:
* [`console_log`](https://docs.rs/console_log/*/console_log/)
* For dynamic libraries:
* You may need to construct [an FFI-safe wrapper over `log`](https://github.com/rust-lang/log/issues/421) to initialize in your libraries.
* Utilities:
* [`log_err`](https://docs.rs/log_err/*/log_err/)
Executables should choose a logger implementation and initialize it early in the
runtime of the program. Logger implementations will typically include a
@ -90,28 +84,3 @@ function to do this. Any log messages generated before the logger is
initialized will be ignored.
The executable itself may use the `log` crate to log as well.
## Structured logging
If you enable the `kv_unstable` feature, you can associate structured data with your log records:
```rust
use log::{info, trace, warn, as_serde, as_error};
pub fn shave_the_yak(yak: &mut Yak) {
trace!(target = "yak_events", yak = as_serde!(yak); "Commencing yak shaving");
loop {
match find_a_razor() {
Ok(razor) => {
info!(razor = razor; "Razor located");
yak.shave(razor);
break;
}
Err(err) => {
warn!(err = as_error!(err); "Unable to locate a razor, retrying");
}
}
}
}
```

View File

@ -33,10 +33,7 @@ fn target_has_atomic_cas(target: &str) -> bool {
fn target_has_atomics(target: &str) -> bool {
match &target[..] {
"thumbv4t-none-eabi"
| "msp430-none-elf"
| "riscv32i-unknown-none-elf"
| "riscv32imc-unknown-none-elf" => false,
"msp430-none-elf" | "riscv32i-unknown-none-elf" | "riscv32imc-unknown-none-elf" => false,
_ => true,
}
}

View File

@ -11,7 +11,6 @@ enum Inner {
#[cfg(feature = "std")]
Boxed(std_support::BoxedError),
Msg(&'static str),
Value(value_bag::Error),
Fmt,
}
@ -22,24 +21,6 @@ impl Error {
inner: Inner::Msg(msg),
}
}
// Not public so we don't leak the `value_bag` API
pub(super) fn from_value(err: value_bag::Error) -> Self {
Error {
inner: Inner::Value(err),
}
}
// Not public so we don't leak the `value_bag` API
pub(super) fn into_value(self) -> value_bag::Error {
match self.inner {
Inner::Value(err) => err,
#[cfg(feature = "kv_unstable_std")]
_ => value_bag::Error::boxed(self),
#[cfg(not(feature = "kv_unstable_std"))]
_ => value_bag::Error::msg("error inspecting a value"),
}
}
}
impl fmt::Display for Error {
@ -48,7 +29,6 @@ impl fmt::Display for Error {
match &self.inner {
#[cfg(feature = "std")]
&Boxed(ref err) => err.fmt(f),
&Value(ref err) => err.fmt(f),
&Msg(ref msg) => msg.fmt(f),
&Fmt => fmt::Error.fmt(f),
}

View File

@ -37,49 +37,6 @@ impl<'v> ToValue for Value<'v> {
}
}
/// Get a value from a type implementing `std::fmt::Debug`.
#[macro_export]
macro_rules! as_debug {
($capture:expr) => {
$crate::kv::Value::from_debug(&$capture)
};
}
/// Get a value from a type implementing `std::fmt::Display`.
#[macro_export]
macro_rules! as_display {
($capture:expr) => {
$crate::kv::Value::from_display(&$capture)
};
}
/// Get a value from an error.
#[cfg(feature = "kv_unstable_std")]
#[macro_export]
macro_rules! as_error {
($capture:expr) => {
$crate::kv::Value::from_dyn_error(&$capture)
};
}
#[cfg(feature = "kv_unstable_serde")]
/// Get a value from a type implementing `serde::Serialize`.
#[macro_export]
macro_rules! as_serde {
($capture:expr) => {
$crate::kv::Value::from_serde(&$capture)
};
}
/// Get a value from a type implementing `sval::value::Value`.
#[cfg(feature = "kv_unstable_sval")]
#[macro_export]
macro_rules! as_sval {
($capture:expr) => {
$crate::kv::Value::from_sval(&$capture)
};
}
/// A value in a structured key-value pair.
///
/// # Capturing values
@ -306,78 +263,6 @@ impl<'v> Value<'v> {
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
self.inner.downcast_ref::<T>()
}
/// Inspect this value using a simple visitor.
pub fn visit(&self, visitor: impl Visit<'v>) -> Result<(), Error> {
struct Visitor<V>(V);
impl<'v, V> value_bag::visit::Visit<'v> for Visitor<V>
where
V: Visit<'v>,
{
fn visit_any(&mut self, value: ValueBag) -> Result<(), value_bag::Error> {
self.0
.visit_any(Value { inner: value })
.map_err(Error::into_value)
}
fn visit_u64(&mut self, value: u64) -> Result<(), value_bag::Error> {
self.0.visit_u64(value).map_err(Error::into_value)
}
fn visit_i64(&mut self, value: i64) -> Result<(), value_bag::Error> {
self.0.visit_i64(value).map_err(Error::into_value)
}
fn visit_u128(&mut self, value: u128) -> Result<(), value_bag::Error> {
self.0.visit_u128(value).map_err(Error::into_value)
}
fn visit_i128(&mut self, value: i128) -> Result<(), value_bag::Error> {
self.0.visit_i128(value).map_err(Error::into_value)
}
fn visit_f64(&mut self, value: f64) -> Result<(), value_bag::Error> {
self.0.visit_f64(value).map_err(Error::into_value)
}
fn visit_bool(&mut self, value: bool) -> Result<(), value_bag::Error> {
self.0.visit_bool(value).map_err(Error::into_value)
}
fn visit_str(&mut self, value: &str) -> Result<(), value_bag::Error> {
self.0.visit_str(value).map_err(Error::into_value)
}
fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), value_bag::Error> {
self.0.visit_borrowed_str(value).map_err(Error::into_value)
}
fn visit_char(&mut self, value: char) -> Result<(), value_bag::Error> {
self.0.visit_char(value).map_err(Error::into_value)
}
#[cfg(feature = "kv_unstable_std")]
fn visit_error(
&mut self,
err: &(dyn std::error::Error + 'static),
) -> Result<(), value_bag::Error> {
self.0.visit_error(err).map_err(Error::into_value)
}
#[cfg(feature = "kv_unstable_std")]
fn visit_borrowed_error(
&mut self,
err: &'v (dyn std::error::Error + 'static),
) -> Result<(), value_bag::Error> {
self.0.visit_borrowed_error(err).map_err(Error::into_value)
}
}
self.inner
.visit(&mut Visitor(visitor))
.map_err(Error::from_value)
}
}
impl<'v> fmt::Debug for Value<'v> {
@ -441,62 +326,12 @@ impl ToValue for str {
}
}
impl ToValue for u128 {
fn to_value(&self) -> Value {
Value::from(self)
}
}
impl ToValue for i128 {
fn to_value(&self) -> Value {
Value::from(self)
}
}
impl ToValue for std::num::NonZeroU128 {
fn to_value(&self) -> Value {
Value::from(self)
}
}
impl ToValue for std::num::NonZeroI128 {
fn to_value(&self) -> Value {
Value::from(self)
}
}
impl<'v> From<&'v str> for Value<'v> {
fn from(value: &'v str) -> Self {
Value::from_value_bag(value)
}
}
impl<'v> From<&'v u128> for Value<'v> {
fn from(value: &'v u128) -> Self {
Value::from_value_bag(value)
}
}
impl<'v> From<&'v i128> for Value<'v> {
fn from(value: &'v i128) -> Self {
Value::from_value_bag(value)
}
}
impl<'v> From<&'v std::num::NonZeroU128> for Value<'v> {
fn from(v: &'v std::num::NonZeroU128) -> Value<'v> {
// SAFETY: `NonZeroU128` and `u128` have the same ABI
Value::from_value_bag(unsafe { std::mem::transmute::<&std::num::NonZeroU128, &u128>(v) })
}
}
impl<'v> From<&'v std::num::NonZeroI128> for Value<'v> {
fn from(v: &'v std::num::NonZeroI128) -> Value<'v> {
// SAFETY: `NonZeroI128` and `i128` have the same ABI
Value::from_value_bag(unsafe { std::mem::transmute::<&std::num::NonZeroI128, &i128>(v) })
}
}
impl ToValue for () {
fn to_value(&self) -> Value {
Value::from_value_bag(())
@ -533,24 +368,6 @@ macro_rules! impl_to_value_primitive {
};
}
macro_rules! impl_to_value_nonzero_primitive {
($($into_ty:ident,)*) => {
$(
impl ToValue for std::num::$into_ty {
fn to_value(&self) -> Value {
Value::from(self.get())
}
}
impl<'v> From<std::num::$into_ty> for Value<'v> {
fn from(value: std::num::$into_ty) -> Self {
Value::from(value.get())
}
}
)*
};
}
macro_rules! impl_value_to_primitive {
($(#[doc = $doc:tt] $into_name:ident -> $into_ty:ty,)*) => {
impl<'v> Value<'v> {
@ -564,12 +381,8 @@ macro_rules! impl_value_to_primitive {
}
}
impl_to_value_primitive![usize, u8, u16, u32, u64, isize, i8, i16, i32, i64, f32, f64, char, bool,];
#[rustfmt::skip]
impl_to_value_nonzero_primitive![
NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64,
NonZeroIsize, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64,
impl_to_value_primitive![
usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64, char, bool,
];
impl_value_to_primitive![
@ -635,142 +448,6 @@ mod std_support {
self.inner.to_str()
}
}
impl<'v> From<&'v String> for Value<'v> {
fn from(v: &'v String) -> Self {
Value::from(&**v)
}
}
}
/// A visitor for a `Value`.
pub trait Visit<'v> {
/// Visit a `Value`.
///
/// This is the only required method on `Visit` and acts as a fallback for any
/// more specific methods that aren't overridden.
/// The `Value` may be formatted using its `fmt::Debug` or `fmt::Display` implementation,
/// or serialized using its `sval::Value` or `serde::Serialize` implementation.
fn visit_any(&mut self, value: Value) -> Result<(), Error>;
/// Visit an unsigned integer.
fn visit_u64(&mut self, value: u64) -> Result<(), Error> {
self.visit_any(value.into())
}
/// Visit a signed integer.
fn visit_i64(&mut self, value: i64) -> Result<(), Error> {
self.visit_any(value.into())
}
/// Visit a big unsigned integer.
fn visit_u128(&mut self, value: u128) -> Result<(), Error> {
self.visit_any((&value).into())
}
/// Visit a big signed integer.
fn visit_i128(&mut self, value: i128) -> Result<(), Error> {
self.visit_any((&value).into())
}
/// Visit a floating point.
fn visit_f64(&mut self, value: f64) -> Result<(), Error> {
self.visit_any(value.into())
}
/// Visit a boolean.
fn visit_bool(&mut self, value: bool) -> Result<(), Error> {
self.visit_any(value.into())
}
/// Visit a string.
fn visit_str(&mut self, value: &str) -> Result<(), Error> {
self.visit_any(value.into())
}
/// Visit a string.
fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> {
self.visit_str(value)
}
/// Visit a Unicode character.
fn visit_char(&mut self, value: char) -> Result<(), Error> {
let mut b = [0; 4];
self.visit_str(&*value.encode_utf8(&mut b))
}
/// Visit an error.
#[cfg(feature = "kv_unstable_std")]
fn visit_error(&mut self, err: &(dyn std::error::Error + 'static)) -> Result<(), Error> {
self.visit_any(Value::from_dyn_error(err))
}
/// Visit an error.
#[cfg(feature = "kv_unstable_std")]
fn visit_borrowed_error(
&mut self,
err: &'v (dyn std::error::Error + 'static),
) -> Result<(), Error> {
self.visit_any(Value::from_dyn_error(err))
}
}
impl<'a, 'v, T: ?Sized> Visit<'v> for &'a mut T
where
T: Visit<'v>,
{
fn visit_any(&mut self, value: Value) -> Result<(), Error> {
(**self).visit_any(value)
}
fn visit_u64(&mut self, value: u64) -> Result<(), Error> {
(**self).visit_u64(value)
}
fn visit_i64(&mut self, value: i64) -> Result<(), Error> {
(**self).visit_i64(value)
}
fn visit_u128(&mut self, value: u128) -> Result<(), Error> {
(**self).visit_u128(value)
}
fn visit_i128(&mut self, value: i128) -> Result<(), Error> {
(**self).visit_i128(value)
}
fn visit_f64(&mut self, value: f64) -> Result<(), Error> {
(**self).visit_f64(value)
}
fn visit_bool(&mut self, value: bool) -> Result<(), Error> {
(**self).visit_bool(value)
}
fn visit_str(&mut self, value: &str) -> Result<(), Error> {
(**self).visit_str(value)
}
fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> {
(**self).visit_borrowed_str(value)
}
fn visit_char(&mut self, value: char) -> Result<(), Error> {
(**self).visit_char(value)
}
#[cfg(feature = "kv_unstable_std")]
fn visit_error(&mut self, err: &(dyn std::error::Error + 'static)) -> Result<(), Error> {
(**self).visit_error(err)
}
#[cfg(feature = "kv_unstable_std")]
fn visit_borrowed_error(
&mut self,
err: &'v (dyn std::error::Error + 'static),
) -> Result<(), Error> {
(**self).visit_borrowed_error(err)
}
}
#[cfg(test)]
@ -792,11 +469,6 @@ pub(crate) mod tests {
Value::from(32u32),
Value::from(64u64),
Value::from(1usize),
Value::from(std::num::NonZeroU8::new(8).unwrap()),
Value::from(std::num::NonZeroU16::new(16).unwrap()),
Value::from(std::num::NonZeroU32::new(32).unwrap()),
Value::from(std::num::NonZeroU64::new(64).unwrap()),
Value::from(std::num::NonZeroUsize::new(1).unwrap()),
]
.into_iter()
}
@ -808,11 +480,6 @@ pub(crate) mod tests {
Value::from(-32i32),
Value::from(-64i64),
Value::from(-1isize),
Value::from(std::num::NonZeroI8::new(-8).unwrap()),
Value::from(std::num::NonZeroI16::new(-16).unwrap()),
Value::from(std::num::NonZeroI32::new(-32).unwrap()),
Value::from(std::num::NonZeroI64::new(-64).unwrap()),
Value::from(std::num::NonZeroIsize::new(-1).unwrap()),
]
.into_iter()
}
@ -985,50 +652,4 @@ pub(crate) mod tests {
assert!(v.is::<Foo>());
assert_eq!(42u64, v.downcast_ref::<Foo>().expect("invalid downcast").0);
}
#[test]
fn test_visit_integer() {
struct Extract(Option<u64>);
impl<'v> Visit<'v> for Extract {
fn visit_any(&mut self, value: Value) -> Result<(), Error> {
unimplemented!("unexpected value: {:?}", value)
}
fn visit_u64(&mut self, value: u64) -> Result<(), Error> {
self.0 = Some(value);
Ok(())
}
}
let mut extract = Extract(None);
Value::from(42u64).visit(&mut extract).unwrap();
assert_eq!(Some(42), extract.0);
}
#[test]
fn test_visit_borrowed_str() {
struct Extract<'v>(Option<&'v str>);
impl<'v> Visit<'v> for Extract<'v> {
fn visit_any(&mut self, value: Value) -> Result<(), Error> {
unimplemented!("unexpected value: {:?}", value)
}
fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> {
self.0 = Some(value);
Ok(())
}
}
let mut extract = Extract(None);
let short_lived = String::from("A short-lived string");
Value::from(&*short_lived).visit(&mut extract).unwrap();
assert_eq!(Some("A short-lived string"), extract.0);
}
}

View File

@ -24,7 +24,7 @@
//! though that default may be overridden. Logger implementations typically use
//! the target to filter requests based on some user configuration.
//!
//! # Usage
//! # Use
//!
//! The basic use of the log crate is through the five logging macros: [`error!`],
//! [`warn!`], [`info!`], [`debug!`] and [`trace!`]
@ -86,42 +86,6 @@
//!
//! The logging system may only be initialized once.
//!
//! ## Structured logging
//!
//! If you enable the `kv_unstable` feature you can associate structured values
//! with your log records. If we take the example from before, we can include
//! some additional context besides what's in the formatted message:
//!
//! ```edition2018
//! # #[macro_use] extern crate serde;
//! # #[derive(Debug, Serialize)] pub struct Yak(String);
//! # impl Yak { fn shave(&mut self, _: u32) {} }
//! # fn find_a_razor() -> Result<u32, std::io::Error> { Ok(1) }
//! # #[cfg(feature = "kv_unstable_serde")]
//! # fn main() {
//! use log::{info, warn, as_serde, as_error};
//!
//! pub fn shave_the_yak(yak: &mut Yak) {
//! info!(target: "yak_events", yak = as_serde!(yak); "Commencing yak shaving");
//!
//! loop {
//! match find_a_razor() {
//! Ok(razor) => {
//! info!(razor = razor; "Razor located");
//! yak.shave(razor);
//! break;
//! }
//! Err(err) => {
//! warn!(err = as_error!(err); "Unable to locate a razor, retrying");
//! }
//! }
//! }
//! }
//! # }
//! # #[cfg(not(feature = "kv_unstable_serde"))]
//! # fn main() {}
//! ```
//!
//! # Available logging implementations
//!
//! In order to produce log output executables have to use
@ -142,14 +106,6 @@
//! * Adaptors for other facilities:
//! * [syslog]
//! * [slog-stdlog]
//! * [systemd-journal-logger]
//! * [android_log]
//! * [win_dbg_logger]
//! * [db_logger]
//! * For WebAssembly binaries:
//! * [console_log]
//! * For dynamic libraries:
//! * You may need to construct an FFI-safe wrapper over `log` to initialize in your libraries
//!
//! # Implementing a Logger
//!
@ -306,18 +262,14 @@
//! [slog-stdlog]: https://docs.rs/slog-stdlog/*/slog_stdlog/
//! [log4rs]: https://docs.rs/log4rs/*/log4rs/
//! [fern]: https://docs.rs/fern/*/fern/
//! [systemd-journal-logger]: https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/
//! [android_log]: https://docs.rs/android_log/*/android_log/
//! [win_dbg_logger]: https://docs.rs/win_dbg_logger/*/win_dbg_logger/
//! [console_log]: https://docs.rs/console_log/*/console_log/
#![doc(
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
html_root_url = "https://docs.rs/log/0.4.17"
html_root_url = "https://docs.rs/log/0.4.14"
)]
#![warn(missing_docs)]
#![deny(missing_debug_implementations, unconditional_recursion)]
#![deny(missing_debug_implementations)]
#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
// When compiled for the rustc compiler itself we want to make sure that this is
// an unstable crate
@ -608,24 +560,6 @@ impl Level {
pub fn as_str(&self) -> &'static str {
LOG_LEVEL_NAMES[*self as usize]
}
/// Iterate through all supported logging levels.
///
/// The order of iteration is from more severe to less severe log messages.
///
/// # Examples
///
/// ```
/// use log::Level;
///
/// let mut levels = Level::iter();
///
/// assert_eq!(Some(Level::Error), levels.next());
/// assert_eq!(Some(Level::Trace), levels.last());
/// ```
pub fn iter() -> impl Iterator<Item = Self> {
(1..6).map(|i| Self::from_usize(i).unwrap())
}
}
/// An enum representing the available verbosity level filters of the logger.
@ -768,7 +702,6 @@ impl LevelFilter {
_ => None,
}
}
/// Returns the most verbose logging level filter.
#[inline]
pub fn max() -> LevelFilter {
@ -789,24 +722,6 @@ impl LevelFilter {
pub fn as_str(&self) -> &'static str {
LOG_LEVEL_NAMES[*self as usize]
}
/// Iterate through all supported filtering levels.
///
/// The order of iteration is from less to more verbose filtering.
///
/// # Examples
///
/// ```
/// use log::LevelFilter;
///
/// let mut levels = LevelFilter::iter();
///
/// assert_eq!(Some(LevelFilter::Off), levels.next());
/// assert_eq!(Some(LevelFilter::Trace), levels.last());
/// ```
pub fn iter() -> impl Iterator<Item = Self> {
(0..6).map(|i| Self::from_usize(i).unwrap())
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
@ -965,7 +880,7 @@ impl<'a> Record<'a> {
self.line
}
/// The structured key-value pairs associated with the message.
/// The structued key-value pairs associated with the message.
#[cfg(feature = "kv_unstable")]
#[inline]
pub fn key_values(&self) -> &dyn kv::Source {
@ -1000,6 +915,7 @@ impl<'a> Record<'a> {
///
/// # Examples
///
///
/// ```edition2018
/// use log::{Level, Record};
///
@ -1273,18 +1189,10 @@ pub trait Log: Sync + Send {
/// This is used by the `log_enabled!` macro to allow callers to avoid
/// expensive computation of log message arguments if the message would be
/// discarded anyway.
///
/// # For implementors
///
/// This method isn't called automatically by the `log!` macros.
/// It's up to an implementation of the `Log` trait to call `enabled` in its own
/// `log` method implementation to guarantee that filtering is applied.
fn enabled(&self, metadata: &Metadata) -> bool;
/// Logs the `Record`.
///
/// # For implementors
///
/// Note that `enabled` is *not* necessarily called before this method.
/// Implementations of `log` should perform all necessary filtering
/// internally.
@ -1306,22 +1214,6 @@ impl Log for NopLogger {
fn flush(&self) {}
}
impl<T> Log for &'_ T
where
T: ?Sized + Log,
{
fn enabled(&self, metadata: &Metadata) -> bool {
(**self).enabled(metadata)
}
fn log(&self, record: &Record) {
(**self).log(record)
}
fn flush(&self) {
(**self).flush()
}
}
#[cfg(feature = "std")]
impl<T> Log for std::boxed::Box<T>
where
@ -1339,31 +1231,12 @@ where
}
}
#[cfg(feature = "std")]
impl<T> Log for std::sync::Arc<T>
where
T: ?Sized + Log,
{
fn enabled(&self, metadata: &Metadata) -> bool {
self.as_ref().enabled(metadata)
}
fn log(&self, record: &Record) {
self.as_ref().log(record)
}
fn flush(&self) {
self.as_ref().flush()
}
}
/// Sets the global maximum log level.
///
/// Generally, this should only be called by the active logging implementation.
///
/// Note that `Trace` is the maximum level, because it provides the maximum amount of detail in the emitted logs.
#[inline]
pub fn set_max_level(level: LevelFilter) {
MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed)
MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::SeqCst)
}
/// Returns the current maximum log level.
@ -1489,8 +1362,6 @@ where
}
INITIALIZING => {
while STATE.load(Ordering::SeqCst) == INITIALIZING {
// TODO: replace with `hint::spin_loop` once MSRV is 1.49.0.
#[allow(deprecated)]
std::sync::atomic::spin_loop_hint();
}
Err(SetLoggerError(()))
@ -1581,39 +1452,10 @@ pub fn logger() -> &'static dyn Log {
// WARNING: this is not part of the crate's public API and is subject to change at any time
#[doc(hidden)]
#[cfg(not(feature = "kv_unstable"))]
pub fn __private_api_log(
args: fmt::Arguments,
level: Level,
&(target, module_path, file, line): &(&str, &'static str, &'static str, u32),
kvs: Option<&[(&str, &str)]>,
) {
if kvs.is_some() {
panic!(
"key-value support is experimental and must be enabled using the `kv_unstable` feature"
)
}
logger().log(
&Record::builder()
.args(args)
.level(level)
.target(target)
.module_path_static(Some(module_path))
.file_static(Some(file))
.line(Some(line))
.build(),
);
}
// WARNING: this is not part of the crate's public API and is subject to change at any time
#[doc(hidden)]
#[cfg(feature = "kv_unstable")]
pub fn __private_api_log(
args: fmt::Arguments,
level: Level,
&(target, module_path, file, line): &(&str, &'static str, &'static str, u32),
kvs: Option<&[(&str, &dyn kv::ToValue)]>,
) {
logger().log(
&Record::builder()
@ -1623,7 +1465,6 @@ pub fn __private_api_log(
.module_path_static(Some(module_path))
.file_static(Some(file))
.line(Some(line))
.key_values(&kvs)
.build(),
);
}
@ -1634,12 +1475,6 @@ pub fn __private_api_enabled(level: Level, target: &str) -> bool {
logger().enabled(&Metadata::builder().level(level).target(target).build())
}
// WARNING: this is not part of the crate's public API and is subject to change at any time
#[doc(hidden)]
pub mod __private_api {
pub use std::option::Option;
}
/// The statically resolved maximum log level.
///
/// See the crate level documentation for information on how to configure this.
@ -1937,35 +1772,4 @@ mod tests {
.expect("invalid value")
);
}
// Test that the `impl Log for Foo` blocks work
// This test mostly operates on a type level, so failures will be compile errors
#[test]
fn test_foreign_impl() {
use super::Log;
#[cfg(feature = "std")]
use std::sync::Arc;
fn assert_is_log<T: Log + ?Sized>() {}
assert_is_log::<&dyn Log>();
#[cfg(feature = "std")]
assert_is_log::<Box<dyn Log>>();
#[cfg(feature = "std")]
assert_is_log::<Arc<dyn Log>>();
// Assert these statements for all T: Log + ?Sized
#[allow(unused)]
fn forall<T: Log + ?Sized>() {
#[cfg(feature = "std")]
assert_is_log::<Box<T>>();
assert_is_log::<&T>();
#[cfg(feature = "std")]
assert_is_log::<Arc<T>>();
}
}
}

View File

@ -29,20 +29,6 @@
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log {
// log!(target: "my_target", Level::Info; key1 = 42, key2 = true; "a {} event", "log");
(target: $target:expr, $lvl:expr, $($key:tt = $value:expr),+; $($arg:tt)+) => ({
let lvl = $lvl;
if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
$crate::__private_api_log(
__log_format_args!($($arg)+),
lvl,
&($target, __log_module_path!(), __log_file!(), __log_line!()),
$crate::__private_api::Option::Some(&[$((__log_key!($key), &$value)),+])
);
}
});
// log!(target: "my_target", Level::Info; "a {} event", "log");
(target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
let lvl = $lvl;
if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
@ -50,13 +36,10 @@ macro_rules! log {
__log_format_args!($($arg)+),
lvl,
&($target, __log_module_path!(), __log_file!(), __log_line!()),
$crate::__private_api::Option::None,
);
}
});
// log!(Level::Info, "a log event")
($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+));
($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+))
}
/// Logs a message at the error level.
@ -75,12 +58,12 @@ macro_rules! log {
/// ```
#[macro_export(local_inner_macros)]
macro_rules! error {
// error!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
// error!(target: "my_target", "a {} event", "log")
(target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Error, $($arg)+));
// error!("a {} event", "log")
($($arg:tt)+) => (log!($crate::Level::Error, $($arg)+))
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Error, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Error, $($arg)+)
)
}
/// Logs a message at the warn level.
@ -99,12 +82,12 @@ macro_rules! error {
/// ```
#[macro_export(local_inner_macros)]
macro_rules! warn {
// warn!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
// warn!(target: "my_target", "a {} event", "log")
(target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Warn, $($arg)+));
// warn!("a {} event", "log")
($($arg:tt)+) => (log!($crate::Level::Warn, $($arg)+))
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Warn, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Warn, $($arg)+)
)
}
/// Logs a message at the info level.
@ -125,12 +108,12 @@ macro_rules! warn {
/// ```
#[macro_export(local_inner_macros)]
macro_rules! info {
// info!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
// info!(target: "my_target", "a {} event", "log")
(target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Info, $($arg)+));
// info!("a {} event", "log")
($($arg:tt)+) => (log!($crate::Level::Info, $($arg)+))
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Info, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Info, $($arg)+)
)
}
/// Logs a message at the debug level.
@ -150,12 +133,12 @@ macro_rules! info {
/// ```
#[macro_export(local_inner_macros)]
macro_rules! debug {
// debug!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
// debug!(target: "my_target", "a {} event", "log")
(target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Debug, $($arg)+));
// debug!("a {} event", "log")
($($arg:tt)+) => (log!($crate::Level::Debug, $($arg)+))
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Debug, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Debug, $($arg)+)
)
}
/// Logs a message at the trace level.
@ -177,12 +160,12 @@ macro_rules! debug {
/// ```
#[macro_export(local_inner_macros)]
macro_rules! trace {
// trace!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
// trace!(target: "my_target", "a {} event", "log")
(target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Trace, $($arg)+));
// trace!("a {} event", "log")
($($arg:tt)+) => (log!($crate::Level::Trace, $($arg)+))
(target: $target:expr, $($arg:tt)+) => (
log!(target: $target, $crate::Level::Trace, $($arg)+)
);
($($arg:tt)+) => (
log!($crate::Level::Trace, $($arg)+)
)
}
/// Determines if a message logged at the specified level in that module will
@ -265,16 +248,3 @@ macro_rules! __log_line {
line!()
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __log_key {
// key1 = 42
($($args:ident)*) => {
stringify!($($args)*)
};
// "key1" = 42
($($args:expr)*) => {
$($args)*
};
}

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"3509b10365d7049c8cce1652272706091dd192cde27d8cb6fa029e46fec8e7c1","build.rs":"a17b1bb1bd3de3fc958f72d4d1357f7bc4432faa26640c95b5fbfccf40579d67","src/codec.rs":"18b1ed94cfd66e29f847b66c73836dfb5be99b3f8a9f40b082acc364f5198743","src/datagram.rs":"569f8d9e34d7ee17144bf63d34136ecd9778da0d337e513f338738c50284615e","src/event.rs":"f60fee9f4b09ef47ff5e4bfa21c07e45ffd5873c292f2605f24d834070127d62","src/header.rs":"b7d4eeb40952b36f71ae1f37ce82c9617af8b84c171576de4eca9d50a3071103","src/hrtime.rs":"c5f9f65a642b5782589a4caaf1e758845daa7ebf56c58dc9ef9f836e48026d29","src/incrdecoder.rs":"458f0228e41018d58f5a83c7895c9ea283f310fcb91c969e22026eb8ca3c84c9","src/lib.rs":"0a3679ab0bc67817097701010881e1c2f48ad1ab0700f12babc46cc59c5c788b","src/log.rs":"f3fb6a1b269a9745b18893a5b31645e541c525f4197cdeec5e9e88abb42c994e","src/qlog.rs":"ca323c91d61810ebef2ebeb967836dda384a60a9fb492c2b8d1b235a98f2e4bf","src/timer.rs":"e63af7e7df968bf702583f263cfb63e6dca4e599bacffa2de0a6383d85333636","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}
{"files":{"Cargo.toml":"9013a62945e20404cfc3624df017feeb3b86e096b6882b0fd2254c4e87d24b6b","build.rs":"a17b1bb1bd3de3fc958f72d4d1357f7bc4432faa26640c95b5fbfccf40579d67","src/codec.rs":"876fe7da558964046765aa2a2d7ebad9d53e1d4b31a1bf233d47b939f417dba1","src/datagram.rs":"569f8d9e34d7ee17144bf63d34136ecd9778da0d337e513f338738c50284615e","src/event.rs":"f60fee9f4b09ef47ff5e4bfa21c07e45ffd5873c292f2605f24d834070127d62","src/header.rs":"b7d4eeb40952b36f71ae1f37ce82c9617af8b84c171576de4eca9d50a3071103","src/hrtime.rs":"45a608ce9f00e2666ce95422a278c6dc0ff4e229b114e7bcf0b4c0d9dc61ad56","src/incrdecoder.rs":"97eb93502afabf13d46de37ca05430c49e876bfa9f013ce264231639eaf9df64","src/lib.rs":"0a3679ab0bc67817097701010881e1c2f48ad1ab0700f12babc46cc59c5c788b","src/log.rs":"b69e492af85e65866cb6588138e8a337dd897d3ce399cb4e9fb8cc04ac042b7f","src/qlog.rs":"ca323c91d61810ebef2ebeb967836dda384a60a9fb492c2b8d1b235a98f2e4bf","src/timer.rs":"e63af7e7df968bf702583f263cfb63e6dca4e599bacffa2de0a6383d85333636","tests/log.rs":"480b165b7907ec642c508b303d63005eee1427115d6973a349eaf6b2242ed18d"},"package":null}

View File

@ -1,14 +1,13 @@
[package]
name = "neqo-common"
version = "0.6.0"
version = "0.5.7"
authors = ["Bobby Holley <bobbyholley@gmail.com>"]
edition = "2018"
rust-version = "1.57.0"
license = "MIT/Apache-2.0"
build = "build.rs"
[dependencies]
log = {version = "0.4.16", default-features = false}
log = {version = "0.4.0", default-features = false}
env_logger = {version = "0.8", default-features = false}
lazy_static = "1.3.0"
qlog = "0.4.0"

View File

@ -6,6 +6,7 @@
use std::convert::TryFrom;
use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
use crate::hex_with_len;
@ -158,18 +159,18 @@ 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> {
// Implement `Deref` for `Decoder` so that values can be examined without moving the cursor.
impl<'a> Deref for Decoder<'a> {
type Target = [u8];
#[must_use]
fn as_ref(&self) -> &'a [u8] {
fn deref(&self) -> &[u8] {
&self.buf[self.offset..]
}
}
impl<'a> Debug for Decoder<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str(&hex_with_len(self.as_ref()))
f.write_str(&hex_with_len(&self[..]))
}
}
@ -247,24 +248,11 @@ impl Encoder {
self.buf.capacity()
}
/// Get the length of the underlying buffer: the number of bytes that have
/// been written to the buffer.
#[must_use]
pub fn len(&self) -> usize {
self.buf.len()
}
/// Returns true if the encoder buffer contains no elements.
#[must_use]
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
/// Create a view of the current contents of the buffer.
/// Note: for a view of a slice, use `Decoder::new(&enc[s..e])`
#[must_use]
pub fn as_decoder(&self) -> Decoder {
Decoder::new(self.as_ref())
Decoder::new(self)
}
/// Don't use this except in testing.
@ -287,7 +275,7 @@ impl Encoder {
/// Generic encode routine for arbitrary data.
pub fn encode(&mut self, data: &[u8]) -> &mut Self {
self.buf.extend_from_slice(data.as_ref());
self.buf.extend_from_slice(data);
self
}
@ -329,7 +317,7 @@ impl Encoder {
/// # Panics
/// 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())
self.encode_uint(n, u64::try_from(v.len()).unwrap())
.encode(v)
}
@ -353,7 +341,7 @@ impl Encoder {
/// # Panics
/// 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.len()).unwrap())
.encode(v)
}
@ -423,12 +411,6 @@ impl AsRef<[u8]> for Encoder {
}
}
impl AsMut<[u8]> for Encoder {
fn as_mut(&mut self) -> &mut [u8] {
self.buf.as_mut()
}
}
impl<'a> From<Decoder<'a>> for Encoder {
#[must_use]
fn from(dec: Decoder<'a>) -> Self {
@ -452,6 +434,20 @@ impl From<Encoder> for Vec<u8> {
}
}
impl Deref for Encoder {
type Target = [u8];
#[must_use]
fn deref(&self) -> &[u8] {
&self.buf[..]
}
}
impl DerefMut for Encoder {
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.buf[..]
}
}
#[cfg(test)]
mod tests {
use super::{Decoder, Encoder};
@ -753,7 +749,7 @@ mod tests {
fn encode_vec_with() {
let mut enc = Encoder::default();
enc.encode_vec_with(2, |enc_inner| {
enc_inner.encode(Encoder::from_hex("02").as_ref());
enc_inner.encode(&Encoder::from_hex("02"));
});
assert_eq!(enc, Encoder::from_hex("000102"));
}
@ -778,7 +774,7 @@ mod tests {
fn encode_vvec_with() {
let mut enc = Encoder::default();
enc.encode_vvec_with(|enc_inner| {
enc_inner.encode(Encoder::from_hex("02").as_ref());
enc_inner.encode(&Encoder::from_hex("02"));
});
assert_eq!(enc, Encoder::from_hex("0102"));
}
@ -798,7 +794,7 @@ mod tests {
fn encode_builder() {
let mut enc = Encoder::from_hex("ff");
let enc2 = Encoder::from_hex("010234");
enc.encode(enc2.as_ref());
enc.encode(&enc2);
assert_eq!(enc, Encoder::from_hex("ff010234"));
}
@ -808,14 +804,14 @@ mod tests {
let mut enc = Encoder::from_hex("ff");
let enc2 = Encoder::from_hex("010234");
let v = enc2.as_decoder();
enc.encode(v.as_ref());
enc.encode(&v);
assert_eq!(enc, Encoder::from_hex("ff010234"));
}
#[test]
fn encode_mutate() {
let mut enc = Encoder::from_hex("010234");
enc.as_mut()[0] = 0xff;
enc[0] = 0xff;
assert_eq!(enc, Encoder::from_hex("ff0234"));
}

View File

@ -82,7 +82,6 @@ impl PeriodSet {
#[allow(non_camel_case_types)]
mod mac {
use std::mem::size_of;
use std::ptr::addr_of_mut;
// These are manually extracted from the many bindings generated
// by bindgen when provided with the simple header:
@ -163,7 +162,7 @@ mod mac {
thread_policy_set(
pthread_mach_thread_np(pthread_self()),
THREAD_TIME_CONSTRAINT_POLICY,
addr_of_mut!(policy) as _, // horror!
&mut policy as *mut thread_time_constraint_policy as *mut _,
THREAD_TIME_CONSTRAINT_POLICY_COUNT,
)
};
@ -198,7 +197,7 @@ mod mac {
thread_policy_get(
pthread_mach_thread_np(pthread_self()),
THREAD_TIME_CONSTRAINT_POLICY,
addr_of_mut!(policy) as _, // horror!
&mut policy as *mut thread_time_constraint_policy as *mut _,
&mut count,
&mut get_default,
)

View File

@ -178,7 +178,7 @@ mod tests {
for tail in 1..db.len() {
let split = db.len() - tail;
let mut dv = Decoder::from(&db.as_ref()[0..split]);
let mut dv = Decoder::from(&db[0..split]);
eprintln!(" split at {}: {:?}", split, dv);
// Clone the basic decoder for each iteration of the loop.
@ -192,7 +192,7 @@ mod tests {
if tail > 1 {
assert_eq!(res, None);
assert!(dec.min_remaining() > 0);
let mut dv = Decoder::from(&db.as_ref()[split..]);
let mut dv = Decoder::from(&db[split..]);
eprintln!(" split remainder {}: {:?}", split, dv);
res = dec.consume(&mut dv);
assert_eq!(dv.remaining(), 1);
@ -230,7 +230,7 @@ mod tests {
#[test]
fn zero_len() {
let enc = Encoder::from_hex("ff");
let mut dec = Decoder::new(enc.as_ref());
let mut dec = Decoder::new(&enc);
let mut incr = IncrementalDecoderBuffer::new(0);
assert_eq!(incr.consume(&mut dec), Some(Vec::new()));
assert_eq!(dec.remaining(), enc.len());
@ -244,7 +244,7 @@ mod tests {
for tail in 1..db.len() {
let split = db.len() - tail;
let mut dv = Decoder::from(&db.as_ref()[0..split]);
let mut dv = Decoder::from(&db[0..split]);
eprintln!(" split at {}: {:?}", split, dv);
// Clone the basic decoder for each iteration of the loop.
@ -256,7 +256,7 @@ mod tests {
if tail > 1 {
assert!(!res);
assert!(dec.min_remaining() > 0);
let mut dv = Decoder::from(&db.as_ref()[split..]);
let mut dv = Decoder::from(&db[split..]);
eprintln!(" split remainder {}: {:?}", split, dv);
res = dec.consume(&mut dv);
assert_eq!(dv.remaining(), 1);

View File

@ -17,7 +17,6 @@ macro_rules! do_log {
::log::__log_format_args!($($arg)+),
lvl,
&($target, ::log::__log_module_path!(), ::log::__log_file!(), ::log::__log_line!()),
None,
);
}
});

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"622b21547b8323877a40dc2661e95b330aee84c0f038a5f28ec3c6dc65f04388","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"cb3e29ac6d1fd7083ffab81494afe1b9a2d9e41c60774438fd9681974c87c252","bindings/mozpkix.hpp":"77072c8bb0f6eb6bfe8cbadc111dcd92e0c79936d13f2e501aae1e5d289a6675","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":"99df86d0c11da5a8cbcc3be2560e6d764234a21b5d9b5f7ab1b70696e4f8670e","src/aead.rs":"140f77ffb5016836c970c39c6c3a42db9581a14b797b9cd05386d0dd0831fe63","src/aead_fuzzing.rs":"4e60d5a2ee6dedfd08602fa36318239e731244825df2cb801ca1d88f5f2a41c1","src/agent.rs":"392ec3a815114c1d83510cf6b4941d3dd427dc69f5ac1a92ab8bf0249aa67fff","src/agentio.rs":"bce4c3dfcfa433209a409ac0c0752f8c95ab37bb6239a42f99b83858e8747bd1","src/auth.rs":"e821dac1511691151a6e64b7c7130a07d941dffad4529b2631f20ddd07d3f20c","src/cert.rs":"628fc2384cdeb2a32bfbecb83c99af393df97fd6a76c6e8827e8240c0d47328b","src/constants.rs":"998e77bee88197a240032c1bfbddcff417a25ba82e576a0d2fe18ee9b63cefc7","src/ech.rs":"447f6297f50914249d0c92ec61d74df6c65ce4affceecb8cafe40927e855fe1d","src/err.rs":"f2cc71de2b40d7bba8119eeaee200337db9a0126176ba06e4902d7312facdb58","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"361277879194dc32f741b8d1894afe5fd3fcc8eb244f7dd5914eeb959b85717d","src/hkdf.rs":"3ff432cc9d40e1dc56e9f983b54b593647c4063a5ae0f16de0a64d033ac9bd94","src/hp.rs":"722a798a7d280b66bd0f8adc6f9135f7d8130f7f0ef45ea12b85d47a88adefda","src/lib.rs":"8d1bfe33999b20eeb5f7eef70d4c634de560de5376029f81b2412bca60176c39","src/once.rs":"b9850384899a1a016e839743d3489c0d4d916e1973746ef8c89872105d7d9736","src/p11.rs":"2ff35a2512bcf894684f24b94640e7fe9d4df6a20264aa3714f2f02fdb99e73d","src/prio.rs":"d9bd43a4d84db70fd552239d0852ea60b960957912f614b929d27dadccca803a","src/replay.rs":"c9bc0261fe1ae22e7212774c315a2669784e57762ca975a15250d4a33dbf3ea3","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"d5d98e34b100568fecade932832379c52530c70a51ad2d37ee6b2dd008865f01","src/selfencrypt.rs":"f11ae7f6f1e6b602b6e729d71597116fb172190b57102af4f76b22fbe78c8b6a","src/ssl.rs":"ace1a162c3b189d52b5e5f9827c4300b7d47d3b2ae29a976d3bbc46c52328253","src/time.rs":"7ea035bb261665c50920ba3dfaaf2582caf5bf3a3464c49b251d15cc39154dc0","tests/aead.rs":"31b5b4374cc5ca2deee6267c4d5b4858defc74e694ec85af196339a76548a17c","tests/agent.rs":"94819f9eeba2afa0c25adc821755900f1488fd47af6d84d9507a112c29d1752a","tests/ext.rs":"eba9f03accdd598e38292ac88263a81b367d60d5a736a43117a3663de105ec48","tests/handshake.rs":"0fcfa8958686aacb42c56c51c6b234842fe990470d2069a67509869baaa18452","tests/hkdf.rs":"47830c1ea58a02d100522bdde6fabc02bb447ccb85affa0cdc44bc25da1be32a","tests/hp.rs":"316973740210fc1f8166920582795a41347a0aec9024fdc480e2ee83a7a5332d","tests/init.rs":"fc9e392b1efa0d8efb28952f73ffc05e5348e7b2b69207b60e375c3888a252a2","tests/selfencrypt.rs":"1125c858ec4e0a6994f34d162aa066cb003c61b324f268529ea04bcb641347cb"},"package":null}
{"files":{"Cargo.toml":"561d34c14380159b08a88a2461a31355e63fbf410725dd28a12bbb3769596675","TODO":"ac0f1c2ebcca03f5b3c0cc56c5aedbb030a4b511e438bc07a57361c789f91e9f","bindings/bindings.toml":"d136f82a333b0ee1499e7858fdfc3d630f7ff37501a3c51028a4eeb7e2f136b4","bindings/mozpkix.hpp":"77072c8bb0f6eb6bfe8cbadc111dcd92e0c79936d13f2e501aae1e5d289a6675","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":"659943cfae3c65be50e92d4b5b499c4580b4c522e9905ba567b434c2081784bc","src/aead.rs":"140f77ffb5016836c970c39c6c3a42db9581a14b797b9cd05386d0dd0831fe63","src/aead_fuzzing.rs":"4e60d5a2ee6dedfd08602fa36318239e731244825df2cb801ca1d88f5f2a41c1","src/agent.rs":"5caad7dfe81b0afbadb4c12e46634961880d12daa4820d9adcfa84c240a36ac2","src/agentio.rs":"bce4c3dfcfa433209a409ac0c0752f8c95ab37bb6239a42f99b83858e8747bd1","src/auth.rs":"e821dac1511691151a6e64b7c7130a07d941dffad4529b2631f20ddd07d3f20c","src/cert.rs":"04d7328ab59a5268f2f48b3f880192bf28d42c09c362ef5906ee66e087c754d1","src/constants.rs":"998e77bee88197a240032c1bfbddcff417a25ba82e576a0d2fe18ee9b63cefc7","src/ech.rs":"1b6ee298855d34310a0d65367b21fdc38678a9c37fc7e1d9579c3c8dfd753377","src/err.rs":"d4dbe63e2faba3a1f08dca015549c32550cb18907592abc3831e05e330f0a93b","src/exp.rs":"61586662407359c1ecb8ed4987bc3c702f26ba2e203a091a51b6d6363cbd510f","src/ext.rs":"361277879194dc32f741b8d1894afe5fd3fcc8eb244f7dd5914eeb959b85717d","src/hkdf.rs":"3ff432cc9d40e1dc56e9f983b54b593647c4063a5ae0f16de0a64d033ac9bd94","src/hp.rs":"46a2023c421d89fda8d09b356b648272857fd20ee5cf5829143ac88402b32e4b","src/lib.rs":"db8cbe315dbfd32c187d63000b15a2fc758104b844714a96e47330bbf746be57","src/once.rs":"b9850384899a1a016e839743d3489c0d4d916e1973746ef8c89872105d7d9736","src/p11.rs":"ae054861719fdead8227220dd5a28b92882756683a436676470b672ee26b9a4e","src/prio.rs":"4224a65f25d7de9bf7d6cb18b15597a39650b3c4fcf7d184a4e4bd7f65cebccd","src/replay.rs":"c9bc0261fe1ae22e7212774c315a2669784e57762ca975a15250d4a33dbf3ea3","src/result.rs":"cef34dfcb907723e195b56501132e4560e250b327783cb5e41201da5b63e9b5c","src/secrets.rs":"48790a330994d892742048000bd12460b7eee2c3daaa444481b8527406d0a4c7","src/selfencrypt.rs":"4a9af42ccefbc77c65baedf00ef389de4fa7ed855d7ab3b60542b5931050667d","src/ssl.rs":"32e934e6dc5df4e4b4cbe96bae53921cf09a684959cb5ad3469cd65965f3164c","src/time.rs":"ddecb9f6cb6b3367852943d27fc89fd36d3c0ca0c9b5c9797494b74de2d8b5c7","tests/aead.rs":"a0fe826aa3bfcce22dbe1b06b74823cb2334331ffe6ce6152952613e9e1ccae5","tests/agent.rs":"94819f9eeba2afa0c25adc821755900f1488fd47af6d84d9507a112c29d1752a","tests/ext.rs":"eba9f03accdd598e38292ac88263a81b367d60d5a736a43117a3663de105ec48","tests/handshake.rs":"0fcfa8958686aacb42c56c51c6b234842fe990470d2069a67509869baaa18452","tests/hkdf.rs":"47830c1ea58a02d100522bdde6fabc02bb447ccb85affa0cdc44bc25da1be32a","tests/hp.rs":"92e062538c01fa7a474225714ed238d846ceb8c8feb9d79eb05be6111b00fb1e","tests/init.rs":"fc9e392b1efa0d8efb28952f73ffc05e5348e7b2b69207b60e375c3888a252a2","tests/selfencrypt.rs":"1125c858ec4e0a6994f34d162aa066cb003c61b324f268529ea04bcb641347cb"},"package":null}

View File

@ -1,9 +1,8 @@
[package]
name = "neqo-crypto"
version = "0.6.0"
version = "0.5.7"
authors = ["Martin Thomson <mt@lowentropy.net>"]
edition = "2018"
rust-version = "1.57.0"
build = "build.rs"
license = "MIT/Apache-2.0"
@ -12,7 +11,7 @@ neqo-common = { path = "../neqo-common" }
log = {version = "0.4.0", default-features = false}
[build-dependencies]
bindgen = {version = "0.59", default-features = false, features= ["runtime"]}
bindgen = {version = "0.56", default-features = false, features= ["runtime"]}
serde = "1.0"
serde_derive = "1.0"
toml = "0.4"

View File

@ -137,7 +137,6 @@ variables = [
types = [
"CERTCertList",
"CERTCertListNode",
"CK_CHACHA20_PARAMS",
"CK_ATTRIBUTE_TYPE",
"CK_FLAGS",
"CK_MECHANISM_TYPE",
@ -151,9 +150,6 @@ functions = [
"CERT_DestroyCertificate",
"CERT_DestroyCertList",
"CERT_GetCertificateDer",
"PK11_CipherOp",
"PK11_CreateContextBySymKey",
"PK11_DestroyContext",
"PK11_Encrypt",
"PK11_ExtractKeyValue",
"PK11_FindCertFromNickname",
@ -188,7 +184,6 @@ enums = [
]
opaque = [
"CERTCertificate",
"PK11Context",
"PK11SlotInfo",
"PK11SymKey",
"SECKEYPrivateKey",
@ -196,16 +191,15 @@ opaque = [
]
variables = [
"CKA_DERIVE",
"CKA_ENCRYPT",
"CKA_VALUE",
"CKF_DERIVE",
"CKM_AES_ECB",
"CKM_AES_GCM",
"CKM_CHACHA20",
"CKM_CHACHA20_POLY1305",
"CKM_EC_KEY_PAIR_GEN",
"CKM_HKDF_DERIVE",
"CKM_INVALID_MECHANISM",
"CKM_NSS_CHACHA20_CTR",
"CKM_NSS_CHACHA20_POLY1305",
"PK11_ATTR_INSENSITIVE",
"PK11_ATTR_PRIVATE",
"PK11_ATTR_PUBLIC",

View File

@ -91,12 +91,7 @@ fn setup_clang() {
fn nss_dir() -> PathBuf {
let dir = if let Ok(dir) = env::var("NSS_DIR") {
let path = PathBuf::from(dir.trim());
assert!(
!path.is_relative(),
"The NSS_DIR environment variable is expected to be an absolute path."
);
path
PathBuf::from(dir.trim())
} else {
let out_dir = env::var("OUT_DIR").unwrap();
let dir = Path::new(&out_dir).join("nss");
@ -261,16 +256,16 @@ fn build_bindings(base: &str, bindings: &Bindings, flags: &[String], gecko: bool
// Apply the configuration.
for v in &bindings.types {
builder = builder.allowlist_type(v);
builder = builder.whitelist_type(v);
}
for v in &bindings.functions {
builder = builder.allowlist_function(v);
builder = builder.whitelist_function(v);
}
for v in &bindings.variables {
builder = builder.allowlist_var(v);
builder = builder.whitelist_var(v);
}
for v in &bindings.exclude {
builder = builder.blocklist_item(v);
builder = builder.blacklist_item(v);
}
for v in &bindings.opaque {
builder = builder.opaque_type(v);

View File

@ -87,11 +87,8 @@ fn get_alpn(fd: *mut ssl::PRFileDesc, pre: bool) -> Res<Option<String>> {
let alpn = match (pre, alpn_state) {
(true, ssl::SSLNextProtoState::SSL_NEXT_PROTO_EARLY_VALUE)
| (
false,
ssl::SSLNextProtoState::SSL_NEXT_PROTO_NEGOTIATED
| ssl::SSLNextProtoState::SSL_NEXT_PROTO_SELECTED,
) => {
| (false, ssl::SSLNextProtoState::SSL_NEXT_PROTO_NEGOTIATED)
| (false, ssl::SSLNextProtoState::SSL_NEXT_PROTO_SELECTED) => {
chosen.truncate(usize::try_from(chosen_len)?);
Some(match String::from_utf8(chosen) {
Ok(a) => a,
@ -805,8 +802,6 @@ impl ResumptionToken {
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.
resumption: Pin<Box<Vec<ResumptionToken>>>,
}
@ -816,15 +811,13 @@ impl Client {
///
/// # Errors
/// Errors returned if the socket can't be created or configured.
pub fn new(server_name: impl Into<String>) -> Res<Self> {
let server_name = server_name.into();
pub fn new(server_name: &str) -> Res<Self> {
let mut agent = SecretAgent::new()?;
let url = CString::new(server_name.as_bytes())?;
let url = CString::new(server_name)?;
secstatus_to_res(unsafe { ssl::SSL_SetURL(agent.fd, url.as_ptr()) })?;
agent.ready(false)?;
let mut client = Self {
agent,
server_name,
resumption: Box::pin(Vec::new()),
};
client.ready()?;
@ -873,11 +866,6 @@ impl Client {
ssl::SECSuccess
}
#[must_use]
pub fn server_name(&self) -> &str {
&self.server_name
}
fn ready(&mut self) -> Res<()> {
let fd = self.fd;
unsafe {

View File

@ -5,7 +5,9 @@
// except according to those terms.
use crate::err::secstatus_to_res;
use crate::p11::{CERTCertListNode, CERT_GetCertificateDer, CertList, Item, SECItem, SECItemArray};
use crate::p11::{
CERTCertListNode, CERT_GetCertificateDer, CertList, Item, PRCList, SECItem, SECItemArray,
};
use crate::ssl::{
PRFileDesc, SSL_PeerCertificateChain, SSL_PeerSignedCertTimestamps,
SSL_PeerStapledOCSPResponses,
@ -13,7 +15,7 @@ use crate::ssl::{
use neqo_common::qerror;
use std::convert::TryFrom;
use std::ptr::{addr_of, NonNull};
use std::ptr::NonNull;
use std::slice;
@ -88,7 +90,7 @@ impl CertificateInfo {
fn head(certs: &CertList) -> *const CERTCertListNode {
// Three stars: one for the reference, one for the wrapper, one to deference the pointer.
unsafe { addr_of!((***certs).list).cast() }
unsafe { (&(***certs).list as *const PRCList).cast() }
}
}

View File

@ -14,7 +14,7 @@ use neqo_common::qtrace;
use std::convert::TryFrom;
use std::ffi::CString;
use std::os::raw::{c_char, c_uint};
use std::ptr::{addr_of_mut, null_mut};
use std::ptr::null_mut;
pub use crate::p11::{HpkeAeadId as AeadId, HpkeKdfId as KdfId, HpkeKemId as KemId};
pub use crate::ssl::HpkeSymmetricSuite as SymmetricSuite;
@ -98,7 +98,6 @@ 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(&params);
// 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) {
@ -106,7 +105,7 @@ pub fn generate_keys() -> Res<(PrivateKey, PublicKey)> {
p11::PK11_GenerateKeyPairWithOpFlags(
*slot,
p11::CK_MECHANISM_TYPE::from(p11::CKM_EC_KEY_PAIR_GEN),
addr_of_mut!(param_item).cast(),
(&mut Item::wrap(&params) as *mut SECItem).cast(),
&mut public_ptr,
p11::PK11_ATTR_SESSION | p11::PK11_ATTR_INSENSITIVE | p11::PK11_ATTR_PUBLIC,
p11::CK_FLAGS::from(p11::CKF_DERIVE),
@ -123,7 +122,7 @@ pub fn generate_keys() -> Res<(PrivateKey, PublicKey)> {
p11::PK11_GenerateKeyPairWithOpFlags(
*slot,
p11::CK_MECHANISM_TYPE::from(p11::CKM_EC_KEY_PAIR_GEN),
addr_of_mut!(param_item).cast(),
(&mut Item::wrap(&params) as *mut SECItem).cast(),
&mut public_ptr,
p11::PK11_ATTR_SESSION | p11::PK11_ATTR_SENSITIVE | p11::PK11_ATTR_PRIVATE,
p11::CK_FLAGS::from(p11::CKF_DERIVE),

View File

@ -29,10 +29,11 @@ pub mod nspr {
pub type Res<T> = Result<T, Error>;
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
#[allow(renamed_and_removed_lints, clippy::pub_enum_variant_names)] // rust 1.54 will require a different approach
pub enum Error {
AeadInitFailure,
AeadError,
CertificateLoading,
CipherInitFailure,
CreateSslSocket,
EchRetry(Vec<u8>),
HkdfError,

View File

@ -9,17 +9,14 @@ use crate::constants::{
};
use crate::err::{secstatus_to_res, Error, Res};
use crate::p11::{
Context, Item, PK11SymKey, PK11_CipherOp, PK11_CreateContextBySymKey, PK11_Encrypt,
PK11_GetBlockSize, SymKey, CKA_ENCRYPT, CKM_AES_ECB, CKM_CHACHA20, CK_ATTRIBUTE_TYPE,
CK_CHACHA20_PARAMS, CK_MECHANISM_TYPE,
Item, PK11SymKey, PK11_Encrypt, PK11_GetBlockSize, PK11_GetMechanism, SECItem, SymKey,
CKM_AES_ECB, CKM_NSS_CHACHA20_CTR, CK_MECHANISM_TYPE,
};
use std::cell::RefCell;
use std::convert::TryFrom;
use std::fmt::{self, Debug};
use std::os::raw::{c_char, c_int, c_uint};
use std::ptr::{addr_of_mut, null, null_mut};
use std::rc::Rc;
use std::os::raw::{c_char, c_uint};
use std::ptr::{null, null_mut};
experimental_api!(SSL_HkdfExpandLabelWithMech(
version: Version,
@ -35,43 +32,29 @@ experimental_api!(SSL_HkdfExpandLabelWithMech(
));
#[derive(Clone)]
pub enum HpKey {
/// An AES encryption context.
/// Note: as we need to clone this object, we clone the pointer and
/// track references using `Rc`. `PK11Context` can't be used with `PK11_CloneContext`
/// as that is not supported for these contexts.
Aes(Rc<RefCell<Context>>),
/// The ChaCha20 mask has to invoke a new PK11_Encrypt every time as it needs to
/// change the counter and nonce on each invocation.
Chacha(SymKey),
}
pub struct HpKey(SymKey);
impl Debug for HpKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "HpKey")
write!(f, "HP-{:?}", self.0)
}
}
impl HpKey {
const SAMPLE_SIZE: usize = 16;
/// QUIC-specific API for extracting a header-protection key.
///
/// # Errors
/// Errors if HKDF fails or if the label is too long to fit in a `c_uint`.
/// # Panics
/// When `cipher` is not known to this code.
#[allow(clippy::cast_sign_loss)] // Cast for PK11_GetBlockSize is safe.
pub fn extract(version: Version, cipher: Cipher, prk: &SymKey, label: &str) -> Res<Self> {
const ZERO: &[u8] = &[0; 12];
let l = label.as_bytes();
let mut secret: *mut PK11SymKey = null_mut();
let (mech, key_size) = match cipher {
TLS_AES_128_GCM_SHA256 => (CK_MECHANISM_TYPE::from(CKM_AES_ECB), 16),
TLS_AES_256_GCM_SHA384 => (CK_MECHANISM_TYPE::from(CKM_AES_ECB), 32),
TLS_CHACHA20_POLY1305_SHA256 => (CK_MECHANISM_TYPE::from(CKM_CHACHA20), 32),
TLS_CHACHA20_POLY1305_SHA256 => (CK_MECHANISM_TYPE::from(CKM_NSS_CHACHA20_CTR), 32),
_ => unreachable!(),
};
@ -91,44 +74,18 @@ impl HpKey {
&mut secret,
)
}?;
let key = SymKey::from_ptr(secret).or(Err(Error::HkdfError))?;
let res = match cipher {
TLS_AES_128_GCM_SHA256 | TLS_AES_256_GCM_SHA384 => {
let context_ptr = unsafe {
PK11_CreateContextBySymKey(
mech,
CK_ATTRIBUTE_TYPE::from(CKA_ENCRYPT),
*key,
&Item::wrap(&ZERO[..0]), // Borrow a zero-length slice of ZERO.
)
};
let context = Context::from_ptr(context_ptr).or(Err(Error::CipherInitFailure))?;
Self::Aes(Rc::new(RefCell::new(context)))
}
TLS_CHACHA20_POLY1305_SHA256 => Self::Chacha(key),
_ => unreachable!(),
};
debug_assert_eq!(
res.block_size(),
usize::try_from(unsafe { PK11_GetBlockSize(mech, null_mut()) }).unwrap()
);
Ok(res)
let sym_key = SymKey::from_ptr(secret).or(Err(Error::HkdfError))?;
Ok(HpKey(sym_key))
}
/// Get the sample size, which is also the output size.
#[allow(clippy::cast_sign_loss)]
#[must_use]
#[allow(clippy::unused_self)] // To maintain an API contract.
pub fn sample_size(&self) -> usize {
Self::SAMPLE_SIZE
}
fn block_size(&self) -> usize {
match self {
Self::Aes(_) => 16,
Self::Chacha(_) => 64,
}
let k: *mut PK11SymKey = *self.0;
let mech = unsafe { PK11_GetMechanism(k) };
// Cast is safe because block size is always greater than or equal to 0
(unsafe { PK11_GetBlockSize(mech, null_mut()) }) as usize
}
/// Generate a header protection mask for QUIC.
@ -139,49 +96,36 @@ impl HpKey {
/// # Panics
/// When the mechanism for our key is not supported.
pub fn mask(&self, sample: &[u8]) -> Res<Vec<u8>> {
let mut output = vec![0_u8; self.block_size()];
let k: *mut PK11SymKey = *self.0;
let mech = unsafe { PK11_GetMechanism(k) };
let block_size = self.sample_size();
match self {
Self::Aes(context) => {
let mut output_len: c_int = 0;
secstatus_to_res(unsafe {
PK11_CipherOp(
**context.borrow_mut(),
output.as_mut_ptr(),
&mut output_len,
c_int::try_from(output.len())?,
(&sample[..Self::SAMPLE_SIZE]).as_ptr().cast(),
c_int::try_from(Self::SAMPLE_SIZE).unwrap(),
)
})?;
assert_eq!(usize::try_from(output_len).unwrap(), output.len());
Ok(output)
}
let mut output = vec![0_u8; block_size];
let output_slice = &mut output[..];
let mut output_len: c_uint = 0;
Self::Chacha(key) => {
let params: CK_CHACHA20_PARAMS = CK_CHACHA20_PARAMS {
pBlockCounter: sample.as_ptr() as *mut u8,
blockCounterBits: 32,
pNonce: (&sample[4..Self::SAMPLE_SIZE]).as_ptr() as *mut _,
ulNonceBits: 96,
};
let mut output_len: c_uint = 0;
let mut param_item = Item::wrap_struct(&params);
secstatus_to_res(unsafe {
PK11_Encrypt(
**key,
CK_MECHANISM_TYPE::from(CKM_CHACHA20),
addr_of_mut!(param_item),
(&mut output[..]).as_mut_ptr(),
&mut output_len,
c_uint::try_from(output.len())?,
(&output[..]).as_ptr(),
c_uint::try_from(output.len())?,
)
})?;
assert_eq!(usize::try_from(output_len).unwrap(), output.len());
Ok(output)
let zero = vec![0_u8; block_size];
let mut wrapped_sample = Item::wrap(sample);
let (iv, inbuf) = match () {
_ if mech == CK_MECHANISM_TYPE::from(CKM_AES_ECB) => (null_mut(), sample),
_ if mech == CK_MECHANISM_TYPE::from(CKM_NSS_CHACHA20_CTR) => {
(&mut wrapped_sample as *mut SECItem, &zero[..])
}
}
_ => unreachable!(),
};
secstatus_to_res(unsafe {
PK11_Encrypt(
k,
mech,
iv,
output_slice.as_mut_ptr(),
&mut output_len,
c_uint::try_from(output.len())?,
inbuf.as_ptr().cast(),
c_uint::try_from(inbuf.len())?,
)
})?;
assert_eq!(output_len as usize, block_size);
Ok(output)
}
}

View File

@ -73,11 +73,10 @@ use std::ffi::CString;
use std::path::{Path, PathBuf};
use std::ptr::null;
const MINIMUM_NSS_VERSION: &str = "3.74";
const MINIMUM_NSS_VERSION: &str = "3.66";
#[allow(non_upper_case_globals, clippy::redundant_static_lifetimes)]
#[allow(clippy::upper_case_acronyms)]
#[allow(unknown_lints, clippy::borrow_as_ptr)]
mod nss {
include!(concat!(env!("OUT_DIR"), "/nss_init.rs"));
}

View File

@ -14,15 +14,13 @@ use crate::err::{secstatus_to_res, Error, Res};
use neqo_common::hex_with_len;
use std::convert::TryFrom;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::os::raw::{c_int, c_uint};
use std::ptr::null_mut;
#[allow(clippy::upper_case_acronyms)]
#[allow(unknown_lints, deref_nullptr)] // Until bindgen#1651 is fixed.
#[allow(unknown_lints, deref_nullptr)] // Until we require rust 1.53 or bindgen#1651 is fixed.
#[allow(clippy::unreadable_literal)]
#[allow(unknown_lints, clippy::borrow_as_ptr)]
mod nss_p11 {
include!(concat!(env!("OUT_DIR"), "/nss_p11.rs"));
}
@ -219,11 +217,6 @@ impl std::fmt::Debug for SymKey {
}
}
unsafe fn destroy_pk11_context(ctxt: *mut PK11Context) {
PK11_DestroyContext(ctxt, PRBool::from(true));
}
scoped_ptr!(Context, PK11Context, destroy_pk11_context);
unsafe fn destroy_secitem(item: *mut SECItem) {
SECITEM_FreeItem(item, PRBool::from(true));
}
@ -232,8 +225,7 @@ scoped_ptr!(Item, SECItem, destroy_secitem);
impl Item {
/// Create a wrapper for a slice of this object.
/// 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`.
/// Minimally, it can only be passed as a `const SECItem*` argument to functions.
pub fn wrap(buf: &[u8]) -> SECItem {
SECItem {
type_: SECItemType::siBuffer,
@ -242,18 +234,6 @@ impl Item {
}
}
/// 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<T>(v: &T) -> SECItem {
SECItem {
type_: SECItemType::siBuffer,
data: (v as *const T as *mut T).cast(),
len: c_uint::try_from(mem::size_of::<T>()).unwrap(),
}
}
/// Make an empty `SECItem` for passing as a mutable `SECItem*` argument.
pub fn make_empty() -> SECItem {
SECItem {

View File

@ -5,16 +5,14 @@
// except according to those terms.
#![allow(clippy::upper_case_acronyms)]
#![allow(unknown_lints, deref_nullptr)] // Until bindgen#1651 is fixed.
#![allow(unknown_lints, deref_nullptr)] // Until we require rust 1.53 or bindgen#1651 is fixed.
#![allow(
dead_code,
non_upper_case_globals,
non_snake_case,
clippy::cognitive_complexity,
clippy::empty_enum,
clippy::too_many_lines,
unknown_lints,
clippy::borrow_as_ptr
clippy::too_many_lines
)]
include!(concat!(env!("OUT_DIR"), "/nspr_io.rs"));

View File

@ -87,7 +87,7 @@ impl Secrets {
}
fn put(&mut self, dir: SecretDirection, epoch: Epoch, key: SymKey) {
qdebug!("{:?} secret available for {:?}: {:?}", dir, epoch, key);
qdebug!("{:?} secret available for {:?}", dir, epoch);
let keys = match dir {
SecretDirection::Read => &mut self.r,
SecretDirection::Write => &mut self.w,

View File

@ -90,7 +90,7 @@ impl SelfEncrypt {
let offset = enc.len();
let mut output: Vec<u8> = enc.into();
output.resize(encoded_len, 0);
cipher.encrypt(0, extended_aad.as_ref(), plaintext, &mut output[offset..])?;
cipher.encrypt(0, &extended_aad, plaintext, &mut output[offset..])?;
qtrace!(
["SelfEncrypt"],
"seal {} {} -> {}",
@ -139,8 +139,7 @@ impl SelfEncrypt {
// NSS insists on having extra space available for decryption.
let padded_len = ciphertext.len() - offset;
let mut output = vec![0; padded_len];
let decrypted =
aead.decrypt(0, extended_aad.as_ref(), &ciphertext[offset..], &mut output)?;
let decrypted = aead.decrypt(0, &extended_aad, &ciphertext[offset..], &mut output)?;
let final_len = decrypted.len();
output.truncate(final_len);
qtrace!(

View File

@ -10,11 +10,9 @@
non_snake_case,
clippy::cognitive_complexity,
clippy::too_many_lines,
clippy::upper_case_acronyms,
unknown_lints,
clippy::borrow_as_ptr
clippy::upper_case_acronyms
)]
#![allow(unknown_lints, deref_nullptr)] // Until bindgen#1651 is fixed.
#![allow(unknown_lints, deref_nullptr)] // Until we require rust 1.53 or bindgen#1651 is fixed.
use crate::constants::Epoch;
use crate::err::{secstatus_to_res, Res};

View File

@ -119,10 +119,8 @@ impl TryInto<PRTime> for Time {
type Error = Error;
fn try_into(self) -> Res<PRTime> {
let base = get_base();
let delta = self
.t
.checked_duration_since(base.instant)
.ok_or(Error::TimeTravelError)?;
// TODO(mt) use checked_duration_since when that is available.
let delta = self.t.duration_since(base.instant);
if let Ok(d) = PRTime::try_from(delta.as_micros()) {
d.checked_add(base.prtime).ok_or(Error::TimeTravelError)
} else {

View File

@ -37,7 +37,7 @@ fn make_aead(cipher: Cipher) -> Aead {
TLS_VERSION_1_3,
cipher,
&secret,
"quic ", // QUICv1 label prefix; note the trailing space here.
"quic ", // Note the trailing space here.
)
.expect("can make an AEAD")
}

View File

@ -2,34 +2,18 @@
#![warn(clippy::pedantic)]
use neqo_crypto::constants::{
Cipher, TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256,
TLS_VERSION_1_3,
Cipher, TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_VERSION_1_3,
};
use neqo_crypto::hkdf;
use neqo_crypto::hp::HpKey;
use std::mem;
use test_fixture::fixture_init;
fn make_hp(cipher: Cipher) -> HpKey {
fixture_init();
let ikm = hkdf::import_key(TLS_VERSION_1_3, &[0; 16]).expect("import IKM");
let prk = hkdf::extract(TLS_VERSION_1_3, cipher, None, &ikm).expect("extract works");
HpKey::extract(TLS_VERSION_1_3, cipher, &prk, "hp").expect("extract label works")
}
fn hp_test(cipher: Cipher, expected: &[u8]) {
let hp = make_hp(cipher);
let mask = hp.mask(&[0; 16]).expect("should produce a mask");
assert_eq!(mask, expected, "first invocation should be correct");
let hp2 = hp.clone();
let mask = hp2.mask(&[0; 16]).expect("clone produces mask");
assert_eq!(mask, expected, "clone should produce the same mask");
let mask = hp.mask(&[0; 16]).expect("should produce a mask again");
assert_eq!(mask, expected, "second invocation should be the same");
}
#[test]
fn aes128() {
const EXPECTED: &[u8] = &[
@ -37,7 +21,11 @@ fn aes128() {
0x14,
];
hp_test(TLS_AES_128_GCM_SHA256, EXPECTED);
fixture_init();
let mask = make_hp(TLS_AES_128_GCM_SHA256)
.mask(&[0; 16])
.expect("should produce a mask");
assert_eq!(mask, EXPECTED);
}
#[test]
@ -47,9 +35,14 @@ fn aes256() {
0x2b,
];
hp_test(TLS_AES_256_GCM_SHA384, EXPECTED);
fixture_init();
let mask = make_hp(TLS_AES_256_GCM_SHA384)
.mask(&[0; 16])
.expect("should produce a mask");
assert_eq!(mask, EXPECTED);
}
#[cfg(feature = "chacha")]
#[test]
fn chacha20_ctr() {
const EXPECTED: &[u8] = &[
@ -60,19 +53,9 @@ fn chacha20_ctr() {
0x2f, 0x52, 0x46, 0x89,
];
hp_test(TLS_CHACHA20_POLY1305_SHA256, EXPECTED);
}
#[test]
#[should_panic]
fn aes_short() {
let hp = make_hp(TLS_AES_128_GCM_SHA256);
mem::drop(hp.mask(&[0; 15]));
}
#[test]
#[should_panic]
fn chacha20_short() {
let hp = make_hp(TLS_CHACHA20_POLY1305_SHA256);
mem::drop(hp.mask(&[0; 15]));
fixture_init();
let mask = make_hp(TLS_CHACHA20_POLY1305_SHA256)
.mask(&[0; 16])
.expect("should produce a mask");
assert_eq!(mask, EXPECTED);
}

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"fa6db9805e426106bbba24a64efbb782c0c3308669ff040ec9085e2fac06ea79","src/buffered_send_stream.rs":"0e4ad4914451943e49c88565661d88475ab2bbd8756e200e2a19312bafd64847","src/client_events.rs":"9d86145febad2f3fb05007eae3f5ad4834c78dd709fe388f05590405e34a614b","src/conn_params.rs":"7e33526de9c83c163049a2caf2bff0f997351cc61fad76fb6e8c6ec4b9f09938","src/connection.rs":"72c3c2a3c19481d519f4c1928c51dc7c1d4ab6e6cb2bd9ecfdfc5d5c09f485bb","src/connection_client.rs":"e4914a8e44eb6045615382eacf2499b0195574f19ce36e161ad3d3e186f69ebb","src/connection_server.rs":"de1e0359b902b1e98c923a8d5488302a68a3312b466590fdddaee6ec8327813b","src/control_stream_local.rs":"b86e1f869ad59bf2663501942a1a65d94c1dbc3e8770982459e0b620be4b6cf0","src/control_stream_remote.rs":"7a261ac7df77e90a428ab0f92457a934a92a8c581462fc1818efd3de0c0ebd69","src/features/extended_connect/mod.rs":"2bc2f0570b11318f3225173001dad1a5f05e4bf60dee49a2bf9d40e3a411e138","src/features/extended_connect/webtransport_session.rs":"abf84892c429c2ee79efd8e215bfd9da182163ba859cd24b6ee4ba6becceb6bd","src/features/extended_connect/webtransport_streams.rs":"784c5e317bb6af33f653ba82c1a5666b657c2a210263a415e913494f61613464","src/features/mod.rs":"a981ebbd03e7bb7ea2313e883452e44f052c48f28edb7fd53a0825911b490230","src/frames/hframe.rs":"da4829b30303d02fd044729a3f6571c596eaa66dceaf51c3a833c61497d6736b","src/frames/mod.rs":"258dd4bdf2daca19a62cd697d2c7f4709a35668b2b4dce3203675e814c9b40b8","src/frames/reader.rs":"0802cd8b41204bcec424fc6ed704a3bdbed0e5d38444f7a9b0550ad877b076a6","src/frames/tests/hframe.rs":"33a30bb98bb512606a06ae1752e1ed9e4588b7d3f5e9439ec83bb2e779d4ac80","src/frames/tests/mod.rs":"4933c519069ee4dac23587588f2b792c12d1363e92d0105e1eb169082e213559","src/frames/tests/reader.rs":"312a3deda7b3a4bbd7afed879c94d0644fce8e34435365ef9cae1fbaa62496af","src/frames/tests/wtframe.rs":"589ebe1e62ce4da63b37b7d22cde7ba572ddbf29336fdcdbbcd0a745f79dacd8","src/frames/wtframe.rs":"1d87964fe76945bfe3e59834632ce1e3a000b5e26164b71bdcd129f8a4e73ae3","src/headers_checks.rs":"b80c1da2d9f336fa88f7b7f2a834d8e90e826260811771c7729785fdc92b20d4","src/lib.rs":"5ac7d69f04b3d748b2a566271fed0a21c2e510e54532a298d5fd8096c8d7a49a","src/priority.rs":"ae0fa461031893b4f7e0d12666072e7a4da80b1e8a1c0663ab9f9e27b3242754","src/push_controller.rs":"aa2a64180d8cb1b87682d0d8bbc42167188e8e1890261cb4cabb76de1fcc708b","src/qlog.rs":"44b6cdbb1d9d6ca47b793e9dbe531b8fdbd40147375f7e4c89aeab536c5d286b","src/qpack_decoder_receiver.rs":"75008d8ea5d538ee34aca4df72e58489417604ccafb61b064280782d6754dd0d","src/qpack_encoder_receiver.rs":"f95cc7d49e4d442b93d522f14ddfc581629664d84d6e13d03a520e855bbe442d","src/recv_message.rs":"5f70fb474e387653d7982374131b3b0c08417509469f273ccebf842bfcee836f","src/request_target.rs":"9182b641f7a7b55272e0e2e872d24a35b1207f35399221b08b899857c3e873ab","src/send_message.rs":"9e1b22ede2a105a79d7c02178801e1a46b06a80dc1c0d2a7d69b0eea7e89f319","src/server.rs":"ab00f395f7767d733091af3e3317527e5c302b2e5062b33943211ede75f10109","src/server_connection_events.rs":"3d89c2d9a30ee719acfbaae4b7720cb354eb73b11bc6ceb44571d68b05192b8b","src/server_events.rs":"3081fdd1e1950aeecae031452cd683335fb0a9dcec51722e614c5939f747b9d9","src/settings.rs":"8a8919cd31683f476dec281b8b545ea3cedb0c7d60cd1e29b097bae605822d47","src/stream_type_reader.rs":"a294dab84f06d375890ba908296bb19251b1ff32f7155e4952ca0a69f0660539","tests/httpconn.rs":"f8d6e6a693d17cf2eb192a730e6fc929bd2814552356ce8d4423a0e3eac8c59d","tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","tests/priority.rs":"a606e5fa03451e09e28c7d5f1820ee85a4567e3969a1690c979761e62123bf54","tests/send_message.rs":"673ae1d0bf2dce46c21ee8353f45f189d2cb64a2f6e137ae38da6b2262ad066e","tests/webtransport/mod.rs":"635c0b0fe682a844f4366335a40b8b3a6539abe30843ee1bcfaf87a34b1d476c","tests/webtransport/negotiation.rs":"2da85dfd45e3dfdbab7608768d734e1f150e1b0ba14e982cbb6de16ba62789c2","tests/webtransport/sessions.rs":"5b4d8483ac018ad5a28adad5e778e2ed48db9c441d1354f6cf21d8e5c6f1a8b3","tests/webtransport/streams.rs":"fd5f075d93f0241290566f59f747d95530d2df579890fd0f6b9e79a557c89a67"},"package":null}
{"files":{"Cargo.toml":"9ff10a0f34e30e86b9c005058e50ba588b39a78330ece04e29e8b1e3ef060471","src/buffered_send_stream.rs":"0e4ad4914451943e49c88565661d88475ab2bbd8756e200e2a19312bafd64847","src/client_events.rs":"9d86145febad2f3fb05007eae3f5ad4834c78dd709fe388f05590405e34a614b","src/conn_params.rs":"00e3f42636f482f91cd6b86d7bebaa85a9f0407143503767fffb66a3cdfbbe43","src/connection.rs":"ef2e70c08a59a8a60c7852c8beb6545e3cb37d8da94302798bdc2fc38e4f76c0","src/connection_client.rs":"fabd645653c5991b8d2ec6f2a3c4e16e32c4faa292da47f5c5eb405ef39f8a7a","src/connection_server.rs":"de1e0359b902b1e98c923a8d5488302a68a3312b466590fdddaee6ec8327813b","src/control_stream_local.rs":"9ceb1aae8079dfca8e2f38fb555d47e84f3001d9501f2c909e8245841974f49c","src/control_stream_remote.rs":"7a261ac7df77e90a428ab0f92457a934a92a8c581462fc1818efd3de0c0ebd69","src/features/extended_connect/mod.rs":"2bc2f0570b11318f3225173001dad1a5f05e4bf60dee49a2bf9d40e3a411e138","src/features/extended_connect/webtransport_session.rs":"791734e1891bd35541be33cbf744d6edee6278e760fedb12839dd052a0cf91ba","src/features/extended_connect/webtransport_streams.rs":"784c5e317bb6af33f653ba82c1a5666b657c2a210263a415e913494f61613464","src/features/mod.rs":"a981ebbd03e7bb7ea2313e883452e44f052c48f28edb7fd53a0825911b490230","src/frames/hframe.rs":"67018ad85ecb9ec0476dafc4b25f6b7015e49531cd19f8e81d204af0e29ee3ea","src/frames/mod.rs":"258dd4bdf2daca19a62cd697d2c7f4709a35668b2b4dce3203675e814c9b40b8","src/frames/reader.rs":"0802cd8b41204bcec424fc6ed704a3bdbed0e5d38444f7a9b0550ad877b076a6","src/frames/tests/hframe.rs":"33a30bb98bb512606a06ae1752e1ed9e4588b7d3f5e9439ec83bb2e779d4ac80","src/frames/tests/mod.rs":"fd2e9d4a28c3bd2fd349f4e3844cefa37e9addb09561e9261b393ca7a37e6c6e","src/frames/tests/reader.rs":"312a3deda7b3a4bbd7afed879c94d0644fce8e34435365ef9cae1fbaa62496af","src/frames/tests/wtframe.rs":"589ebe1e62ce4da63b37b7d22cde7ba572ddbf29336fdcdbbcd0a745f79dacd8","src/frames/wtframe.rs":"1d87964fe76945bfe3e59834632ce1e3a000b5e26164b71bdcd129f8a4e73ae3","src/headers_checks.rs":"0893d48fde97687b712e86457e75f2a1b802e7589ce38df30ff65684d8cf59c0","src/lib.rs":"4876915dd7f03021cce3a166e12e0a3763ac2c44e6ad81d223cda1f555b7a2c2","src/priority.rs":"ae0fa461031893b4f7e0d12666072e7a4da80b1e8a1c0663ab9f9e27b3242754","src/push_controller.rs":"aa2a64180d8cb1b87682d0d8bbc42167188e8e1890261cb4cabb76de1fcc708b","src/qlog.rs":"44b6cdbb1d9d6ca47b793e9dbe531b8fdbd40147375f7e4c89aeab536c5d286b","src/qpack_decoder_receiver.rs":"75008d8ea5d538ee34aca4df72e58489417604ccafb61b064280782d6754dd0d","src/qpack_encoder_receiver.rs":"f95cc7d49e4d442b93d522f14ddfc581629664d84d6e13d03a520e855bbe442d","src/recv_message.rs":"5f70fb474e387653d7982374131b3b0c08417509469f273ccebf842bfcee836f","src/request_target.rs":"9182b641f7a7b55272e0e2e872d24a35b1207f35399221b08b899857c3e873ab","src/send_message.rs":"f3503bf135af5acdb3663a8b591b1db2d160e3dcec37aafd2053f2f150f68d2a","src/server.rs":"3cde23011de0a63ee4900e41368e9319ce100a1584f90bf5463e054adcc8875c","src/server_connection_events.rs":"3d89c2d9a30ee719acfbaae4b7720cb354eb73b11bc6ceb44571d68b05192b8b","src/server_events.rs":"3081fdd1e1950aeecae031452cd683335fb0a9dcec51722e614c5939f747b9d9","src/settings.rs":"8a8919cd31683f476dec281b8b545ea3cedb0c7d60cd1e29b097bae605822d47","src/stream_type_reader.rs":"d63727341d925241ec17c7373d81145aba1464cac4c9eedfc05f24c453435f67","tests/httpconn.rs":"f8d6e6a693d17cf2eb192a730e6fc929bd2814552356ce8d4423a0e3eac8c59d","tests/mod.rs":"fd6aee37243713e80fc526552f21f0222338cec9890409b6575a2a637b17ec1f","tests/priority.rs":"a606e5fa03451e09e28c7d5f1820ee85a4567e3969a1690c979761e62123bf54","tests/send_message.rs":"673ae1d0bf2dce46c21ee8353f45f189d2cb64a2f6e137ae38da6b2262ad066e","tests/webtransport/mod.rs":"635c0b0fe682a844f4366335a40b8b3a6539abe30843ee1bcfaf87a34b1d476c","tests/webtransport/negotiation.rs":"fd46a3a77c75dfb701ac075cdb0aabb58f82b5d5c03c5a965412bbf6ad020f00","tests/webtransport/sessions.rs":"5b4d8483ac018ad5a28adad5e778e2ed48db9c441d1354f6cf21d8e5c6f1a8b3","tests/webtransport/streams.rs":"fd5f075d93f0241290566f59f747d95530d2df579890fd0f6b9e79a557c89a67"},"package":null}

View File

@ -1,9 +1,8 @@
[package]
name = "neqo-http3"
version = "0.6.0"
version = "0.5.7"
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
edition = "2018"
rust-version = "1.57.0"
license = "MIT/Apache-2.0"
[dependencies]

View File

@ -14,7 +14,7 @@ const QPACK_MAX_BLOCKED_STREAMS_DEFAULT: u16 = 20;
const MAX_PUSH_STREAM_DEFAULT: u64 = 0;
const WEBTRANSPORT_DEFAULT: bool = false;
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy)]
pub struct Http3Parameters {
conn_params: ConnectionParameters,
qpack_settings: QpackSettings,

View File

@ -203,8 +203,8 @@ impl Http3Connection {
self.qpack_decoder.borrow_mut().send(conn)?;
match self.qpack_encoder.borrow_mut().send_encoder_updates(conn) {
Ok(())
| Err(neqo_qpack::Error::EncoderStreamBlocked | neqo_qpack::Error::DynamicTableFull) => {
}
| Err(neqo_qpack::Error::EncoderStreamBlocked)
| Err(neqo_qpack::Error::DynamicTableFull) => {}
Err(e) => return Err(Error::QpackError(e)),
}
Ok(())
@ -300,9 +300,9 @@ impl Http3Connection {
}
Ok(ReceiveOutput::ControlFrames(rest))
}
ReceiveOutput::NewStream(
NewStreamType::Push(_) | NewStreamType::Http | NewStreamType::WebTransportStream(_),
) => Ok(output),
ReceiveOutput::NewStream(NewStreamType::Push(_))
| ReceiveOutput::NewStream(NewStreamType::Http)
| ReceiveOutput::NewStream(NewStreamType::WebTransportStream(_)) => Ok(output),
ReceiveOutput::NewStream(_) => {
unreachable!("NewStream should have been handled already")
}
@ -355,7 +355,7 @@ impl Http3Connection {
match state {
State::Handshaking => {
if self.role == Role::Server
&& conn.zero_rtt_state() == ZeroRttState::AcceptedServer
&& conn.zero_rtt_state() == &ZeroRttState::AcceptedServer
{
self.state = Http3State::ZeroRtt;
self.initialize_http3_connection(conn)?;

View File

@ -22,7 +22,7 @@ use neqo_crypto::{agent::CertificateInfo, AuthenticationStatus, ResumptionToken,
use neqo_qpack::Stats as QpackStats;
use neqo_transport::{
AppError, Connection, ConnectionEvent, ConnectionId, ConnectionIdGenerator, Output,
Stats as TransportStats, StreamId, StreamType, Version, ZeroRttState,
QuicVersion, Stats as TransportStats, StreamId, StreamType, ZeroRttState,
};
use std::cell::RefCell;
use std::fmt::Debug;
@ -49,13 +49,13 @@ where
}
}
fn alpn_from_quic_version(version: Version) -> &'static str {
fn alpn_from_quic_version(version: QuicVersion) -> &'static str {
match version {
Version::Version2 | Version::Version1 => "h3",
Version::Draft29 => "h3-29",
Version::Draft30 => "h3-30",
Version::Draft31 => "h3-31",
Version::Draft32 => "h3-32",
QuicVersion::Version1 => "h3",
QuicVersion::Draft29 => "h3-29",
QuicVersion::Draft30 => "h3-30",
QuicVersion::Draft31 => "h3-31",
QuicVersion::Draft32 => "h3-32",
}
}
@ -77,7 +77,7 @@ impl Http3Client {
/// Making a `neqo-transport::connection` may produce an error. This can only be a crypto error if
/// the socket can't be created or configured.
pub fn new(
server_name: impl Into<String>,
server_name: &str,
cid_manager: Rc<RefCell<dyn ConnectionIdGenerator>>,
local_addr: SocketAddr,
remote_addr: SocketAddr,
@ -90,13 +90,12 @@ impl Http3Client {
&[alpn_from_quic_version(
http3_parameters
.get_connection_parameters()
.get_versions()
.initial(),
.get_quic_version(),
)],
cid_manager,
local_addr,
remote_addr,
http3_parameters.get_connection_parameters().clone(),
*http3_parameters.get_connection_parameters(),
now,
)?,
http3_parameters,
@ -106,16 +105,17 @@ impl Http3Client {
#[must_use]
pub fn new_with_conn(c: Connection, http3_parameters: Http3Parameters) -> Self {
let events = Http3ClientEvents::default();
let webtransport = http3_parameters.get_webtransport();
let push_streams = http3_parameters.get_max_concurrent_push_streams();
let mut base_handler = Http3Connection::new(http3_parameters, Role::Client);
if webtransport {
if http3_parameters.get_webtransport() {
base_handler.set_features_listener(events.clone());
}
Self {
conn: c,
events: events.clone(),
push_handler: Rc::new(RefCell::new(PushController::new(push_streams, events))),
push_handler: Rc::new(RefCell::new(PushController::new(
http3_parameters.get_max_concurrent_push_streams(),
events,
))),
base_handler,
}
}
@ -219,7 +219,7 @@ impl Http3Client {
debug_assert_eq!(Ok(true), res);
return Err(Error::FatalError);
}
if self.conn.zero_rtt_state() == ZeroRttState::Sending {
if *self.conn.zero_rtt_state() == ZeroRttState::Sending {
self.base_handler
.set_0rtt_settings(&mut self.conn, settings)?;
self.events
@ -834,16 +834,17 @@ mod tests {
use neqo_common::{event::Provider, qtrace, Datagram, Decoder, Encoder};
use neqo_crypto::{AllowZeroRtt, AntiReplay, ResumptionToken};
use neqo_qpack::{encoder::QPackEncoder, QpackSettings};
use neqo_transport::tparams::{self, TransportParameter};
use neqo_transport::{
ConnectionError, ConnectionEvent, ConnectionParameters, Output, State, StreamId,
StreamType, Version, RECV_BUFFER_SIZE, SEND_BUFFER_SIZE,
StreamType, RECV_BUFFER_SIZE, SEND_BUFFER_SIZE,
};
use std::convert::TryFrom;
use std::mem;
use std::time::Duration;
use test_fixture::{
addr, anti_replay, default_server_h3, fixture_init, new_server, now,
CountingConnectionIdGenerator, DEFAULT_ALPN_H3, DEFAULT_KEYS, DEFAULT_SERVER_NAME,
addr, anti_replay, default_server_h3, fixture_init, now, CountingConnectionIdGenerator,
DEFAULT_ALPN_H3, DEFAULT_KEYS, DEFAULT_SERVER_NAME,
};
fn assert_closed(client: &Http3Client, expected: &Error) {
@ -868,11 +869,6 @@ mod tests {
addr(),
addr(),
Http3Parameters::default()
.connection_parameters(
// Disable compatible upgrade, which complicates tests.
ConnectionParameters::default()
.versions(Version::default(), vec![Version::default()]),
)
.max_table_size_encoder(max_table_size)
.max_table_size_decoder(max_table_size)
.max_blocked_streams(100)
@ -1021,9 +1017,9 @@ mod tests {
self.settings.encode(&mut enc);
assert_eq!(
self.conn
.stream_send(self.control_stream_id.unwrap(), enc.as_ref())
.stream_send(self.control_stream_id.unwrap(), &enc[..])
.unwrap(),
enc.len()
enc[..].len()
);
}
@ -1164,10 +1160,19 @@ mod tests {
.borrow_mut()
.encode_header_block(&mut self.conn, headers, stream_id);
let hframe = HFrame::Headers {
header_block: header_block.as_ref().to_vec(),
header_block: header_block.to_vec(),
};
hframe.encode(encoder);
}
pub fn set_max_uni_stream(&mut self, max_stream: u64) {
self.conn
.set_local_tparam(
tparams::INITIAL_MAX_STREAMS_UNI,
TransportParameter::Integer(max_stream),
)
.unwrap();
}
}
fn handshake_only(client: &mut Http3Client, server: &mut TestServer) -> Output {
@ -1419,13 +1424,10 @@ mod tests {
client: &mut Http3Client,
server: &mut TestServer,
stream_id: StreamId,
response: impl AsRef<[u8]>,
response: &[u8],
close_stream: bool,
) {
let _ = server
.conn
.stream_send(stream_id, response.as_ref())
.unwrap();
let _ = server.conn.stream_send(stream_id, response).unwrap();
if close_stream {
server.conn.stream_close_send(stream_id).unwrap();
}
@ -1457,7 +1459,7 @@ mod tests {
};
let mut d = Encoder::default();
frame.encode(&mut d);
let _ = conn.stream_send(stream_id, d.as_ref()).unwrap();
let _ = conn.stream_send(stream_id, &d).unwrap();
}
fn send_push_data_and_exchange_packets(
@ -1498,7 +1500,7 @@ mod tests {
frame.encode(&mut d);
server
.conn
.stream_send(server.control_stream_id.unwrap(), d.as_ref())
.stream_send(server.control_stream_id.unwrap(), &d)
.unwrap();
let out = server.conn.process(None, now());
@ -1534,13 +1536,13 @@ mod tests {
conn: &mut Connection,
push_stream_id: StreamId,
push_id: u8,
data: impl AsRef<[u8]>,
data: &[u8],
close_push_stream: bool,
) {
// send data
let _ = conn.stream_send(push_stream_id, PUSH_STREAM_TYPE).unwrap();
let _ = conn.stream_send(push_stream_id, &[push_id]).unwrap();
let _ = conn.stream_send(push_stream_id, data.as_ref()).unwrap();
let _ = conn.stream_send(push_stream_id, data).unwrap();
if close_push_stream {
conn.stream_close_send(push_stream_id).unwrap();
}
@ -2410,7 +2412,7 @@ mod tests {
let mut enc = Encoder::default();
data_frame.encode(&mut enc);
(vec![0_u8; size], enc.as_ref().to_vec())
(vec![0_u8; size], enc.to_vec())
}
// Send 2 frames. For the second one we can only send 63 bytes.
@ -3890,7 +3892,7 @@ mod tests {
server.settings.encode(&mut enc);
let mut sent = server.conn.stream_send(control_stream, CONTROL_STREAM_TYPE);
assert_eq!(sent.unwrap(), CONTROL_STREAM_TYPE.len());
sent = server.conn.stream_send(control_stream, enc.as_ref());
sent = server.conn.stream_send(control_stream, &enc);
assert_eq!(sent.unwrap(), enc.len());
let out = server.conn.process(None, now());
@ -4529,10 +4531,7 @@ mod tests {
let d_frame = HFrame::Data { len: 3 };
d_frame.encode(&mut d);
d.encode(&[0x61, 0x62, 0x63]);
let _ = server
.conn
.stream_send(request_stream_id, d.as_ref())
.unwrap();
let _ = server.conn.stream_send(request_stream_id, &d[..]).unwrap();
server.conn.stream_close_send(request_stream_id).unwrap();
let out = server.conn.process(None, now());
@ -6088,9 +6087,9 @@ mod tests {
for f in H3_RESERVED_FRAME_TYPES {
let mut enc = Encoder::default();
enc.encode_varint(*f);
test_wrong_frame_on_control_stream(enc.as_ref());
test_wrong_frame_on_push_stream(enc.as_ref());
test_wrong_frame_on_request_stream(enc.as_ref());
test_wrong_frame_on_control_stream(&enc);
test_wrong_frame_on_push_stream(&enc);
test_wrong_frame_on_request_stream(&enc);
}
}
@ -6111,7 +6110,7 @@ mod tests {
// The settings frame contains a reserved settings type and some value (0x1).
enc.encode_varint(*s);
enc.encode_varint(1_u64);
let sent = server.conn.stream_send(control_stream, enc.as_ref());
let sent = server.conn.stream_send(control_stream, &enc);
assert_eq!(sent, Ok(4));
let out = server.conn.process(None, now());
client.process(out.dgram(), now());
@ -6370,10 +6369,8 @@ mod tests {
#[test]
fn client_control_stream_create_failed() {
let mut client = default_http3_client();
let mut server = TestServer::new_with_conn(new_server(
DEFAULT_ALPN_H3,
ConnectionParameters::default().max_streams(StreamType::UniDi, 0),
));
let mut server = TestServer::new();
server.set_max_uni_stream(0);
handshake_client_error(&mut client, &mut server, &Error::StreamLimitError);
}
@ -6381,10 +6378,8 @@ mod tests {
#[test]
fn client_qpack_stream_create_failed() {
let mut client = default_http3_client();
let mut server = TestServer::new_with_conn(new_server(
DEFAULT_ALPN_H3,
ConnectionParameters::default().max_streams(StreamType::UniDi, 2),
));
let mut server = TestServer::new();
server.set_max_uni_stream(2);
handshake_client_error(&mut client, &mut server, &Error::StreamLimitError);
}

View File

@ -39,7 +39,7 @@ impl ControlStreamLocal {
pub fn queue_frame(&mut self, f: &HFrame) {
let mut enc = Encoder::default();
f.encode(&mut enc);
self.stream.buffer(enc.as_ref());
self.stream.buffer(&enc);
}
pub fn queue_update_priority(&mut self, stream_id: StreamId) {
@ -80,7 +80,7 @@ impl ControlStreamLocal {
if let Some(hframe) = stream.priority_update_frame() {
let mut enc = Encoder::new();
hframe.encode(&mut enc);
if self.stream.send_atomic(conn, enc.as_ref())? {
if self.stream.send_atomic(conn, &enc)? {
stream.priority_update_sent();
} else {
self.outstanding_priority_update.push_front(update_id);

View File

@ -377,8 +377,7 @@ impl WebTransportSession {
};
let mut encoder = Encoder::default();
close_frame.encode(&mut encoder);
self.control_stream_send
.send_data_atomic(conn, encoder.as_ref())?;
self.control_stream_send.send_data_atomic(conn, &encoder)?;
self.control_stream_send.close(conn)?;
self.state = if self.control_stream_send.done() {
SessionState::Done

View File

@ -138,7 +138,7 @@ impl HFrame {
update_frame.encode(&priority_enc);
enc.encode_varint(update_frame.len() as u64);
enc.encode(update_frame.as_ref());
enc.encode(&update_frame);
}
}
}

View File

@ -17,7 +17,7 @@ use test_fixture::{default_client, default_server, now};
pub fn enc_dec<T: FrameDecoder<T>>(d: &Encoder, st: &str, remaining: usize) -> T {
// For data, headers and push_promise we do not read all bytes from the buffer
let d2 = Encoder::from_hex(st);
assert_eq!(d.as_ref(), &d2.as_ref()[..d.as_ref().len()]);
assert_eq!(&d[..], &d2[..d.len()]);
let mut conn_c = default_client();
let mut conn_s = default_server();
@ -36,7 +36,7 @@ pub fn enc_dec<T: FrameDecoder<T>>(d: &Encoder, st: &str, remaining: usize) -> T
// conver string into u8 vector
let buf = Encoder::from_hex(st);
conn_s.stream_send(stream_id, buf.as_ref()).unwrap();
conn_s.stream_send(stream_id, &buf[..]).unwrap();
let out = conn_s.process(None, now());
mem::drop(conn_c.process(out.dgram(), now()));

View File

@ -114,7 +114,7 @@ pub fn headers_valid(headers: &[Header], message_type: MessageType) -> Res<()> {
let pseudo_header_mask = match message_type {
MessageType::Response => enum_set!(PseudoHeaderState::Status),
MessageType::Request => {
if method_value == Some("CONNECT") {
if method_value == Some(&"CONNECT".to_string()) {
PseudoHeaderState::Method | PseudoHeaderState::Authority
} else {
PseudoHeaderState::Method | PseudoHeaderState::Scheme | PseudoHeaderState::Path
@ -124,7 +124,7 @@ pub fn headers_valid(headers: &[Header], message_type: MessageType) -> Res<()> {
if (MessageType::Request == message_type)
&& pseudo_state.contains(PseudoHeaderState::Protocol)
&& method_value != Some("CONNECT")
&& method_value != Some(&"CONNECT".to_string())
{
return Err(Error::InvalidHeader);
}

View File

@ -60,6 +60,11 @@ pub use stream_type_reader::NewStreamType;
type Res<T> = Result<T, Error>;
#[derive(Clone, Debug, PartialEq)]
#[allow(
renamed_and_removed_lints,
clippy::pub_enum_variant_names,
clippy::enum_variant_names
)]
pub enum Error {
HttpNoError,
HttpGeneralProtocol,
@ -148,7 +153,8 @@ impl Error {
| Self::HttpId
| Self::HttpSettings
| Self::HttpMissingSettings
| Self::QpackError(QpackError::EncoderStream | QpackError::DecoderStream)
| Self::QpackError(QpackError::EncoderStream)
| Self::QpackError(QpackError::DecoderStream)
)
}
@ -162,9 +168,10 @@ impl Error {
#[must_use]
pub fn map_stream_send_errors(err: &Error) -> Self {
match err {
Self::TransportError(
TransportError::InvalidStreamId | TransportError::FinalSizeError,
) => Error::TransportStreamDoesNotExist,
Self::TransportError(TransportError::InvalidStreamId)
| Self::TransportError(TransportError::FinalSizeError) => {
Error::TransportStreamDoesNotExist
}
Self::TransportError(TransportError::InvalidInput) => Error::InvalidInput,
_ => {
debug_assert!(false, "Unexpected error");

View File

@ -210,7 +210,7 @@ impl SendStream for SendMessage {
data_frame.encode(&mut enc);
let sent_fh = self
.stream
.send_atomic(conn, enc.as_ref())
.send_atomic(conn, &enc)
.map_err(|e| Error::map_stream_send_errors(&e))?;
debug_assert!(sent_fh);
@ -300,7 +300,7 @@ impl SendStream for SendMessage {
};
let mut enc = Encoder::default();
data_frame.encode(&mut enc);
self.stream.buffer(enc.as_ref());
self.stream.buffer(&enc);
self.stream.buffer(buf);
mem::drop(self.stream.send_buffer(conn)?);
Ok(())

View File

@ -62,9 +62,9 @@ impl Http3Server {
protocols,
anti_replay,
zero_rtt_checker
.unwrap_or_else(|| Box::new(HttpZeroRttChecker::new(http3_parameters.clone()))),
.unwrap_or_else(|| Box::new(HttpZeroRttChecker::new(http3_parameters))),
cid_manager,
http3_parameters.get_connection_parameters().clone(),
*http3_parameters.get_connection_parameters(),
)?,
http3_parameters,
http3_handlers: HashMap::new(),
@ -150,12 +150,10 @@ impl Http3Server {
fn process_events(&mut self, conn: &mut ActiveConnectionRef, now: Instant) {
let mut remove = false;
let http3_parameters = &self.http3_parameters;
let http3_parameters = self.http3_parameters;
{
let handler = self.http3_handlers.entry(conn.clone()).or_insert_with(|| {
Rc::new(RefCell::new(Http3ServerHandler::new(
http3_parameters.clone(),
)))
Rc::new(RefCell::new(Http3ServerHandler::new(http3_parameters)))
});
handler
.borrow_mut()
@ -344,7 +342,12 @@ mod tests {
fn assert_closed(hconn: &mut Http3Server, expected: &Error) {
let err = ConnectionError::Application(expected.code());
let closed = |e| matches!(e, Http3ServerEvent::StateChange{ state: Http3State::Closing(e) | Http3State::Closed(e), .. } if e == err);
let closed = |e| {
matches!(e,
Http3ServerEvent::StateChange{ state: Http3State::Closing(e), .. }
| Http3ServerEvent::StateChange{ state: Http3State::Closed(e), .. }
if e == err)
};
assert!(hconn.events().any(closed));
}
@ -611,7 +614,7 @@ mod tests {
};
let mut e = Encoder::default();
frame.encode(&mut e);
peer_conn.control_send(e.as_ref());
peer_conn.control_send(&e);
let out = peer_conn.process(None, now());
hconn.process(out.dgram(), now());
// check if the given connection got closed on invalid stream ids
@ -1140,7 +1143,7 @@ mod tests {
/// Perform a handshake, then another with the token from the first.
/// The second should always resume, but it might not always accept early data.
fn zero_rtt_with_settings(conn_params: Http3Parameters, zero_rtt: ZeroRttState) {
fn zero_rtt_with_settings(conn_params: Http3Parameters, zero_rtt: &ZeroRttState) {
let (_, mut client) = connect();
let token = client.events().find_map(|e| {
if let ConnectionEvent::ResumptionToken(token) = e {
@ -1162,7 +1165,7 @@ mod tests {
#[test]
fn zero_rtt() {
zero_rtt_with_settings(http3params(DEFAULT_SETTINGS), ZeroRttState::AcceptedClient);
zero_rtt_with_settings(http3params(DEFAULT_SETTINGS), &ZeroRttState::AcceptedClient);
}
/// A larger QPACK decoder table size isn't an impediment to 0-RTT.
@ -1173,7 +1176,7 @@ mod tests {
max_table_size_decoder: DEFAULT_SETTINGS.max_table_size_decoder + 1,
..DEFAULT_SETTINGS
}),
ZeroRttState::AcceptedClient,
&ZeroRttState::AcceptedClient,
);
}
@ -1185,7 +1188,7 @@ mod tests {
max_table_size_decoder: DEFAULT_SETTINGS.max_table_size_decoder - 1,
..DEFAULT_SETTINGS
}),
ZeroRttState::Rejected,
&ZeroRttState::Rejected,
);
}
@ -1197,7 +1200,7 @@ mod tests {
max_blocked_streams: DEFAULT_SETTINGS.max_blocked_streams + 1,
..DEFAULT_SETTINGS
}),
ZeroRttState::AcceptedClient,
&ZeroRttState::AcceptedClient,
);
}
@ -1209,7 +1212,7 @@ mod tests {
max_blocked_streams: DEFAULT_SETTINGS.max_blocked_streams - 1,
..DEFAULT_SETTINGS
}),
ZeroRttState::Rejected,
&ZeroRttState::Rejected,
);
}
@ -1221,7 +1224,7 @@ mod tests {
max_table_size_encoder: DEFAULT_SETTINGS.max_table_size_encoder - 1,
..DEFAULT_SETTINGS
}),
ZeroRttState::AcceptedClient,
&ZeroRttState::AcceptedClient,
);
}
@ -1301,6 +1304,6 @@ mod tests {
connect_transport(&mut server, &mut client, true);
assert!(client.tls_info().unwrap().resumed());
assert_eq!(client.zero_rtt_state(), ZeroRttState::Rejected);
assert_eq!(client.zero_rtt_state(), &ZeroRttState::Rejected);
}
}

View File

@ -59,6 +59,7 @@ impl NewStreamType {
}
(_, StreamType::BiDi, Role::Server) => Err(Error::HttpFrame),
(HTTP3_UNI_STREAM_TYPE_PUSH, StreamType::UniDi, Role::Server)
| (H3_FRAME_TYPE_HEADERS, StreamType::BiDi, Role::Client)
| (_, StreamType::BiDi, Role::Client) => Err(Error::HttpStreamCreation),
_ => Ok(Some(NewStreamType::Unknown)),
}
@ -196,13 +197,13 @@ impl NewStreamHeadReader {
fn map_stream_fin(decoded: Option<NewStreamType>) -> Res<Option<NewStreamType>> {
match decoded {
Some(NewStreamType::Control | NewStreamType::Encoder | NewStreamType::Decoder) => {
Err(Error::HttpClosedCriticalStream)
}
Some(NewStreamType::Control)
| Some(NewStreamType::Encoder)
| Some(NewStreamType::Decoder) => Err(Error::HttpClosedCriticalStream),
None => Err(Error::HttpStreamCreation),
Some(NewStreamType::Http) => Err(Error::HttpFrame),
Some(NewStreamType::Unknown) => Ok(decoded),
Some(NewStreamType::Push(_) | NewStreamType::WebTransportStream(_)) => {
Some(NewStreamType::Push(_)) | Some(NewStreamType::WebTransportStream(_)) => {
unreachable!("PushStream and WebTransport are mapped to None at this stage.")
}
}
@ -317,7 +318,7 @@ mod tests {
for i in to_encode {
enc.encode_varint(*i);
}
self.decode_buffer(enc.as_ref(), fin, outcome, done);
self.decode_buffer(&enc[..], fin, outcome, done);
}
}

View File

@ -139,8 +139,8 @@ fn wrong_setting_value() {
};
settings.encode(&mut enc);
assert_eq!(
server.stream_send(control, enc.as_ref()).unwrap(),
enc.as_ref().len()
server.stream_send(control, &enc[..]).unwrap(),
enc[..].len()
);
exchange_packets2(&mut client, &mut server);

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"be8c8af80d916302d316e9e457bb3dc7a9f9469f4f15fb89d7eb1d5e8f1bad3d","src/decoder.rs":"8bd336c91cca989883106a9d0bf26b117d224e0e7643960c3e97d0168d1853c4","src/decoder_instructions.rs":"19d47158bc09551b449be205f5cd5ea83e6984c4e4d3e7d4b95938b09617015e","src/encoder.rs":"b888a819595fec47037d508b943f5ff04ed52ea376bef1f90e08edc6576e773c","src/encoder_instructions.rs":"a7f1d3a4f8ae941286d0aba81037a8df3ef85e275392ef31d9938e9314c706db","src/header_block.rs":"7910ddc28b44d2065070cb2d87ab3cfbb905cce912b23d8b12b0f0add5691ceb","src/huffman.rs":"3a9edaf827343ec6e43cfd50fcc0d0077287947160ae630da5c3ddaaefedd010","src/huffman_decode_helper.rs":"2970c57f052878b727c2f764490c54184f5c2608e1d6aa961c3b01509e290122","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"4e42b609aabfbe4c19582c13007abbc82a6560c174d56559ea344975c3473454","src/prefix.rs":"72c587c40aef4ed38cf13b2de91091d671611679be2a9da6f0b24abafaf50dc5","src/qlog.rs":"7618085e27bb3fb1f4d1c73ba501b9a293723293c4020b7cc4129676eb278131","src/qpack_send_buf.rs":"49ded6607ec0859cb3edc5a38ff48f4d2d292f0721673d4e20700d07ac324557","src/reader.rs":"be265cc8c317512f266fafdcc835d0e413caf5280a7cc945bfe6e7e849529d67","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"f7091bdd9ad1f8fe3b2298a7dbfd3d285c212d69569cda54f9bcf251cb758a21"},"package":null}
{"files":{"Cargo.toml":"ffbf61e358a81f58d8b4f0ca89031d53879ec8e45851a0f1bc2b583229feb815","src/decoder.rs":"8bd336c91cca989883106a9d0bf26b117d224e0e7643960c3e97d0168d1853c4","src/decoder_instructions.rs":"19d47158bc09551b449be205f5cd5ea83e6984c4e4d3e7d4b95938b09617015e","src/encoder.rs":"e72cbcdbe24cbe13ad5cbcbb0df8981a2ea67331f296ec7784480bc28ae01eef","src/encoder_instructions.rs":"a7f1d3a4f8ae941286d0aba81037a8df3ef85e275392ef31d9938e9314c706db","src/header_block.rs":"7910ddc28b44d2065070cb2d87ab3cfbb905cce912b23d8b12b0f0add5691ceb","src/huffman.rs":"3a9edaf827343ec6e43cfd50fcc0d0077287947160ae630da5c3ddaaefedd010","src/huffman_decode_helper.rs":"2970c57f052878b727c2f764490c54184f5c2608e1d6aa961c3b01509e290122","src/huffman_table.rs":"06fea766a6276ac56c7ee0326faed800a742c15fda1f33bf2513e6cc6a5e6d27","src/lib.rs":"29c5e47f8a4cf9c0a5dfdc614594868db22bc25b9688e5efdbc041cd222a17e5","src/prefix.rs":"72c587c40aef4ed38cf13b2de91091d671611679be2a9da6f0b24abafaf50dc5","src/qlog.rs":"7618085e27bb3fb1f4d1c73ba501b9a293723293c4020b7cc4129676eb278131","src/qpack_send_buf.rs":"49ded6607ec0859cb3edc5a38ff48f4d2d292f0721673d4e20700d07ac324557","src/reader.rs":"be265cc8c317512f266fafdcc835d0e413caf5280a7cc945bfe6e7e849529d67","src/static_table.rs":"fda9d5c6f38f94b0bf92d3afdf8432dce6e27e189736596e16727090c77b78ec","src/stats.rs":"624dfa3b40858c304097bb0ce5b1be1bb4d7916b1abfc222f1aa705907009730","src/table.rs":"f7091bdd9ad1f8fe3b2298a7dbfd3d285c212d69569cda54f9bcf251cb758a21"},"package":null}

View File

@ -1,9 +1,8 @@
[package]
name = "neqo-qpack"
version = "0.6.0"
version = "0.5.7"
authors = ["Dragana Damjanovic <dragana.damjano@gmail.com>"]
edition = "2018"
rust-version = "1.57.0"
license = "MIT/Apache-2.0"
[dependencies]

View File

@ -516,7 +516,7 @@ mod tests {
use crate::QpackSettings;
use neqo_transport::{ConnectionParameters, StreamId, StreamType};
use std::mem;
use test_fixture::{default_client, default_server, handshake, new_server, now, DEFAULT_ALPN};
use test_fixture::{configure_server, default_client, default_server, handshake, now};
struct TestEncoder {
encoder: QPackEncoder,
@ -571,8 +571,7 @@ mod tests {
fn connect_generic(huffman: bool, max_data: Option<u64>) -> TestEncoder {
let mut conn = default_client();
let mut peer_conn = max_data.map_or_else(default_server, |max| {
new_server(
DEFAULT_ALPN,
configure_server(
ConnectionParameters::default()
.max_stream_data(StreamType::UniDi, true, max)
.max_stream_data(StreamType::BiDi, true, max)

View File

@ -39,6 +39,11 @@ pub struct QpackSettings {
}
#[derive(Clone, Debug, PartialEq)]
#[allow(
renamed_and_removed_lints,
clippy::pub_enum_variant_names,
clippy::enum_variant_names
)]
pub enum Error {
DecompressionFailed,
EncoderStream,

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,8 @@
[package]
name = "neqo-transport"
version = "0.6.0"
version = "0.5.7"
authors = ["EKR <ekr@rtfm.com>", "Andy Grover <agrover@mozilla.com>"]
edition = "2018"
rust-version = "1.57.0"
license = "MIT/Apache-2.0"
[dependencies]

View File

@ -127,7 +127,7 @@ impl AddressValidation {
// Include the token identifier ("Retry"/~) in the AAD, then keep it for plaintext.
let mut buf = Self::encode_aad(peer_address, retry);
let encrypted = self.self_encrypt.seal(buf.as_ref(), data.as_ref())?;
let encrypted = self.self_encrypt.seal(&buf, &data)?;
buf.truncate(TOKEN_IDENTIFIER_RETRY.len());
buf.encode(&encrypted);
Ok(buf.into())
@ -165,7 +165,7 @@ impl AddressValidation {
now: Instant,
) -> Option<ConnectionId> {
let peer_addr = Self::encode_aad(peer_address, retry);
let data = self.self_encrypt.open(peer_addr.as_ref(), token).ok()?;
let data = self.self_encrypt.open(&peer_addr, token).ok()?;
let mut dec = Decoder::new(&data);
match dec.decode_uint(4) {
Some(d) => {

View File

@ -152,7 +152,7 @@ impl<T: WindowAdjustment> CongestionControl for ClassicCongestionControl<T> {
let is_app_limited = self.app_limited();
qtrace!(
[self],
"limited={}, bytes_in_flight={}, cwnd={}, state={:?} pacing_burst_size={}",
"app limited={}, bytes_in_flight:{}, cwnd: {}, state: {:?} pacing_burst_size: {}",
is_app_limited,
self.bytes_in_flight,
self.congestion_window,
@ -413,7 +413,7 @@ impl<T: WindowAdjustment> ClassicCongestionControl<T> {
continue;
}
if let Some(t) = start {
if p.time_sent.checked_duration_since(t).unwrap() > pc_period {
if p.time_sent.duration_since(t) > pc_period {
qinfo!([self], "persistent congestion");
self.congestion_window = CWND_MIN;
self.acked_bytes = 0;

View File

@ -450,10 +450,6 @@ impl ConnectionIdManager {
}
}
pub fn generator(&self) -> Rc<RefCell<dyn ConnectionIdGenerator>> {
Rc::clone(&self.generator)
}
pub fn decoder(&self) -> ConnectionIdDecoderRef {
ConnectionIdDecoderRef {
generator: self.generator.deref().borrow(),
@ -492,8 +488,6 @@ impl ConnectionIdManager {
/// During the handshake, a server needs to regard the client's choice of destination
/// connection ID as valid. This function saves it in the store in a special place.
/// Note that this is only done *after* an Initial packet from the client is
/// successfully processed.
pub fn add_odcid(&mut self, cid: ConnectionId) {
let entry = ConnectionIdEntry::new(CONNECTION_ID_SEQNO_ODCID, cid, ());
self.connection_ids.add_local(entry);

View File

@ -41,7 +41,9 @@ use crate::frame::{
CloseError, Frame, FrameType, FRAME_TYPE_CONNECTION_CLOSE_APPLICATION,
FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT,
};
use crate::packet::{DecryptedPacket, PacketBuilder, PacketNumber, PacketType, PublicPacket};
use crate::packet::{
DecryptedPacket, PacketBuilder, PacketNumber, PacketType, PublicPacket, QuicVersion,
};
use crate::path::{Path, PathRef, Paths};
use crate::quic_datagrams::{DatagramTracking, QuicDatagrams};
use crate::recovery::{LossRecovery, RecoveryToken, SendProfile};
@ -50,12 +52,10 @@ pub use crate::send_stream::{RetransmissionPriority, TransmissionPriority};
use crate::stats::{Stats, StatsCell};
use crate::stream_id::StreamType;
use crate::streams::Streams;
use crate::tparams::{
self, TransportParameter, TransportParameterId, TransportParameters, TransportParametersHandler,
};
use crate::tparams::{self, TransportParameter, TransportParameters, TransportParametersHandler};
use crate::tracking::{AckTracker, PacketNumberSpace, SentPacket};
use crate::version::{Version, WireVersion};
use crate::{qlog, AppError, ConnectionError, Error, Res, StreamId};
use crate::{qlog, StreamId};
use crate::{AppError, ConnectionError, Error, Res};
mod idle;
pub mod params;
@ -79,7 +79,7 @@ struct Packet(Vec<u8>);
/// handshake. This is a hack, but a useful one.
const EXTRA_INITIALS: usize = 4;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq)]
pub enum ZeroRttState {
Init,
Sending,
@ -218,7 +218,6 @@ impl AddressValidationInfo {
/// remote) continue processing until `state()` returns `Closed`.
pub struct Connection {
role: Role,
version: Version,
state: State,
tps: Rc<RefCell<TransportParametersHandler>>,
/// What we are doing with 0-RTT.
@ -247,8 +246,6 @@ pub struct Connection {
/// when they are either just reordered or we haven't been able to install keys yet.
/// In particular, this occurs when asynchronous certificate validation happens.
saved_datagrams: SavedDatagrams,
/// Some packets were received, but not tracked.
received_untracked: bool,
/// This is responsible for the QuicDatagrams' handling:
/// https://datatracker.ietf.org/doc/html/draft-ietf-quic-datagram
@ -296,7 +293,7 @@ impl Connection {
/// Create a new QUIC connection with Client role.
pub fn new_client(
server_name: impl Into<String>,
server_name: &str,
protocols: &[impl AsRef<str>],
cid_generator: Rc<RefCell<dyn ConnectionIdGenerator>>,
local_addr: SocketAddr,
@ -307,16 +304,12 @@ impl Connection {
let dcid = ConnectionId::generate_initial();
let mut c = Self::new(
Role::Client,
Agent::from(Client::new(server_name.into())?),
Client::new(server_name)?.into(),
cid_generator,
protocols,
conn_params,
)?;
c.crypto.states.init(
c.conn_params.get_versions().compatible(),
Role::Client,
&dcid,
);
c.crypto.states.init(c.version(), Role::Client, &dcid);
c.original_destination_cid = Some(dcid);
let path = Path::temporary(
local_addr,
@ -338,18 +331,18 @@ impl Connection {
) -> Res<Self> {
Self::new(
Role::Server,
Agent::from(Server::new(certs)?),
Server::new(certs)?.into(),
cid_generator,
protocols,
conn_params,
)
}
fn new<P: AsRef<str>>(
fn new(
role: Role,
agent: Agent,
cid_generator: Rc<RefCell<dyn ConnectionIdGenerator>>,
protocols: &[P],
protocols: &[impl AsRef<str>],
conn_params: ConnectionParameters,
) -> Res<Self> {
// Setup the local connection ID.
@ -367,9 +360,9 @@ impl Connection {
let tphandler = Rc::new(RefCell::new(tps));
let crypto = Crypto::new(
conn_params.get_versions().initial(),
conn_params.get_quic_version(),
agent,
protocols.iter().map(P::as_ref).map(String::from).collect(),
protocols,
Rc::clone(&tphandler),
)?;
@ -384,7 +377,6 @@ impl Connection {
let c = Self {
role,
version: conn_params.get_versions().initial(),
state: State::Init,
paths: Paths::default(),
cid_manager,
@ -395,7 +387,6 @@ impl Connection {
remote_initial_source_cid: None,
original_destination_cid: None,
saved_datagrams: SavedDatagrams::default(),
received_untracked: false,
crypto,
acks: AckTracker::default(),
idle_timeout: IdleTimeout::new(conn_params.get_idle_timeout()),
@ -466,15 +457,13 @@ impl Connection {
}
/// Set a local transport parameter, possibly overriding a default value.
/// This only sets transport parameters without dealing with other aspects of
/// setting the value.
/// # Panics
/// This panics if the transport parameter is known to this crate.
pub fn set_local_tparam(&self, tp: TransportParameterId, value: TransportParameter) -> Res<()> {
#[cfg(not(test))]
{
assert!(!tparams::INTERNAL_TRANSPORT_PARAMETERS.contains(&tp));
}
/// In general, this method should not be used. This only sets transport parameters
/// without dealing with other aspects of setting the value.
pub fn set_local_tparam(
&self,
tp: crate::tparams::TransportParameterId,
value: TransportParameter,
) -> Res<()> {
if *self.state() == State::Init {
self.tps.borrow_mut().local.set(tp, value);
Ok(())
@ -549,7 +538,6 @@ impl Connection {
.remote
.as_ref()
.expect("should have transport parameters"),
self.version,
u64::try_from(rtt.as_millis()).unwrap_or(0),
)
.unwrap()
@ -650,13 +638,6 @@ impl Connection {
);
let mut dec = Decoder::from(token.as_ref());
let version =
Version::try_from(dec.decode_uint(4).ok_or(Error::InvalidResumptionToken)? as u32)?;
qtrace!([self], " version {:?}", version);
if !self.conn_params.get_versions().all().contains(&version) {
return Err(Error::DisabledVersion);
}
let rtt = Duration::from_millis(dec.decode_varint().ok_or(Error::InvalidResumptionToken)?);
qtrace!([self], " RTT {:?}", rtt);
@ -671,7 +652,6 @@ impl Connection {
let tok = dec.decode_remainder();
qtrace!([self], " TLS token {}", hex(&tok));
match self.crypto.tls {
Agent::Client(ref mut c) => {
let res = c.enable_resumption(&tok);
@ -683,9 +663,6 @@ impl Connection {
Agent::Server(_) => return Err(Error::WrongRole),
}
self.version = version;
self.conn_params.get_versions_mut().set_initial(version);
self.tps.borrow_mut().set_version(version);
self.tps.borrow_mut().remote_0rtt = Some(tp);
if !init_token.is_empty() {
self.address_validation = AddressValidationInfo::NewToken(init_token.to_vec());
@ -718,7 +695,7 @@ impl Connection {
tps.borrow().local.encode(enc_inner);
});
enc.encode(extra);
let records = s.send_ticket(now, enc.as_ref())?;
let records = s.send_ticket(now, &enc)?;
qinfo!([self], "send session ticket {}", hex(&enc));
self.crypto.buffer_records(records)?;
} else {
@ -763,7 +740,7 @@ impl Connection {
pub fn authenticated(&mut self, status: AuthenticationStatus, now: Instant) {
qinfo!([self], "Authenticated {:?}", status);
self.crypto.tls.authenticated(status);
let res = self.handshake(now, self.version, PacketNumberSpace::Handshake, None);
let res = self.handshake(now, PacketNumberSpace::Handshake, None);
self.absorb_error(now, res);
self.process_saved(now);
}
@ -779,13 +756,13 @@ impl Connection {
}
/// The QUIC version in use.
pub fn version(&self) -> Version {
self.version
pub fn version(&self) -> QuicVersion {
self.conn_params.get_quic_version()
}
/// Get the 0-RTT state of the connection.
pub fn zero_rtt_state(&self) -> ZeroRttState {
self.zero_rtt_state
pub fn zero_rtt_state(&self) -> &ZeroRttState {
&self.zero_rtt_state
}
/// Get a snapshot of collected statistics.
@ -1023,7 +1000,7 @@ impl Connection {
self.process_output(now)
}
fn handle_retry(&mut self, packet: &PublicPacket, now: Instant) {
fn handle_retry(&mut self, packet: &PublicPacket) {
qinfo!([self], "received Retry");
if matches!(self.address_validation, AddressValidationInfo::Retry { .. }) {
self.stats.borrow_mut().pkt_dropped("Extra Retry");
@ -1052,14 +1029,12 @@ impl Connection {
retry_scid
);
let lost_packets = self.loss_recovery.retry(&path, now);
let lost_packets = self.loss_recovery.retry(&path);
self.handle_lost_packets(&lost_packets);
self.crypto.states.init(
self.conn_params.get_versions().compatible(),
self.role,
&retry_scid,
);
self.crypto
.states
.init(self.version(), self.role, &retry_scid);
self.address_validation = AddressValidationInfo::Retry {
token: packet.token().to_vec(),
retry_source_cid: retry_scid,
@ -1111,7 +1086,7 @@ impl Connection {
fn process_saved(&mut self, now: Instant) {
while let Some(cspace) = self.saved_datagrams.available() {
qdebug!([self], "process saved for space {:?}", cspace);
debug_assert!(self.crypto.states.rx_hp(self.version, cspace).is_some());
debug_assert!(self.crypto.states.rx_hp(cspace).is_some());
for saved in self.saved_datagrams.take_saved() {
qtrace!([self], "input saved @{:?}: {:?}", saved.t, saved.d);
self.input(saved.d, saved.t, now);
@ -1131,44 +1106,6 @@ impl Connection {
self.stats.borrow_mut().saved_datagrams += 1;
}
/// Perform version negotiation.
fn version_negotiation(&mut self, supported: &[WireVersion], now: Instant) -> Res<()> {
debug_assert_eq!(self.role, Role::Client);
if let Some(version) = self.conn_params.get_versions().preferred(supported) {
assert_ne!(self.version, version);
qinfo!([self], "Version negotiation: trying {:?}", version);
let local_addr = self.paths.primary().borrow().local_address();
let remote_addr = self.paths.primary().borrow().remote_address();
let conn_params = self
.conn_params
.clone()
.versions(version, self.conn_params.get_versions().all().to_vec());
let mut c = Self::new_client(
self.crypto.server_name().unwrap(),
self.crypto.protocols(),
self.cid_manager.generator(),
local_addr,
remote_addr,
conn_params,
now,
)?;
c.conn_params
.get_versions_mut()
.set_initial(self.conn_params.get_versions().initial());
mem::swap(self, &mut c);
Ok(())
} else {
qinfo!([self], "Version negotiation: failed with {:?}", supported);
// This error goes straight to closed.
self.set_state(State::Closed(ConnectionError::Transport(
Error::VersionNegotiation,
)));
Err(Error::VersionNegotiation)
}
}
/// Perform any processing that we might have to do on packets prior to
/// attempting to remove protection.
fn preprocess_packet(
@ -1198,10 +1135,7 @@ impl Connection {
match (packet.packet_type(), &self.state, &self.role) {
(PacketType::Initial, State::Init, Role::Server) => {
let version = *packet.version().as_ref().unwrap();
if !packet.is_valid_initial()
|| !self.conn_params.get_versions().all().contains(&version)
{
if !packet.is_valid_initial() {
self.stats.borrow_mut().pkt_dropped("Invalid Initial");
return Ok(PreprocessResult::Next);
}
@ -1211,12 +1145,10 @@ impl Connection {
packet.scid(),
packet.dcid()
);
// Record the client's selected CID so that it can be accepted until
// the client starts using a real connection ID.
let dcid = ConnectionId::from(packet.dcid());
self.crypto.states.init_server(version, &dcid);
self.original_destination_cid = Some(dcid);
self.set_state(State::WaitInitial);
self.crypto
.states
.init(self.version(), self.role, packet.dcid());
// We need to make sure that we set this transport parameter.
// This has to happen prior to processing the packet so that
@ -1232,9 +1164,8 @@ impl Connection {
match packet.supported_versions() {
Ok(versions) => {
if versions.is_empty()
|| versions.contains(&self.version().wire_version())
|| versions.contains(&0)
|| packet.scid() != self.odcid().unwrap()
|| versions.contains(&self.version().as_u32())
|| packet.dcid() != self.odcid().unwrap()
|| matches!(
self.address_validation,
AddressValidationInfo::Retry { .. }
@ -1247,17 +1178,19 @@ impl Connection {
return Ok(PreprocessResult::End);
}
self.version_negotiation(&versions, now)?;
return Ok(PreprocessResult::End);
self.set_state(State::Closed(ConnectionError::Transport(
Error::VersionNegotiation,
)));
return Err(Error::VersionNegotiation);
}
Err(_) => {
self.stats.borrow_mut().pkt_dropped("VN with no versions");
self.stats.borrow_mut().pkt_dropped("Invalid VN");
return Ok(PreprocessResult::End);
}
}
}
(PacketType::Retry, State::WaitInitial, Role::Client) => {
self.handle_retry(packet, now);
self.handle_retry(packet);
return Ok(PreprocessResult::Next);
}
(PacketType::Handshake, State::WaitInitial, Role::Client)
@ -1293,7 +1226,7 @@ impl Connection {
PreprocessResult::Next
}
State::WaitInitial => PreprocessResult::Continue,
State::WaitVersion | State::Handshaking | State::Connected | State::Confirmed => {
State::Handshaking | State::Connected | State::Confirmed => {
if !self.cid_manager.is_valid(packet.dcid()) {
self.stats
.borrow_mut()
@ -1336,7 +1269,6 @@ impl Connection {
if self.state == State::WaitInitial {
self.start_handshake(path, packet, now);
}
if self.state.connected() {
self.handle_migration(path, d, migrate, now);
} else if self.role != Role::Client
@ -1433,12 +1365,6 @@ impl Connection {
// Exhausting read keys is fatal.
return Err(e);
}
Error::KeysDiscarded(cspace) => {
// This was a valid-appearing Initial packet: maybe probe with
// a Handshake packet to keep the handshake moving.
self.received_untracked |=
self.role == Role::Client && cspace == CryptoSpace::Initial;
}
_ => (),
}
// Decryption failure, or not having keys is not fatal.
@ -1492,30 +1418,15 @@ impl Connection {
ack_eliciting |= f.ack_eliciting();
probing &= f.path_probing();
let t = f.get_type();
if let Err(e) = self.input_frame(path, packet.version(), packet.packet_type(), f, now) {
if let Err(e) = self.input_frame(path, packet.packet_type(), f, now) {
self.capture_error(Some(Rc::clone(path)), now, t, Err(e))?;
}
}
let largest_received = if let Some(space) = self
let largest_received = self
.acks
.get_mut(PacketNumberSpace::from(packet.packet_type()))
{
space.set_received(now, packet.pn(), ack_eliciting)
} else {
qdebug!(
[self],
"processed a {:?} packet without tracking it",
packet.packet_type(),
);
// This was a valid packet that caused the same packet number to be
// discarded. This happens when the client discards the Initial packet
// number space after receiving the ServerHello. Remember this so
// that we guarantee that we send a Handshake packet.
self.received_untracked = true;
// We don't migrate during the handshake, so return false.
false
};
.unwrap()
.set_received(now, packet.pn(), ack_eliciting);
Ok(largest_received && !probing)
}
@ -1523,7 +1434,6 @@ impl Connection {
/// During connection setup, the first path needs to be setup.
/// This uses the connection IDs that were provided during the handshake
/// to setup that path.
#[allow(clippy::or_fun_call)] // Remove when MSRV >= 1.59
fn setup_handshake_path(&mut self, path: &PathRef, now: Instant) {
self.paths.make_permanent(
path,
@ -1533,7 +1443,7 @@ impl Connection {
ConnectionIdEntry::initial_remote(
self.remote_initial_source_cid
.as_ref()
.or(self.original_destination_cid.as_ref())
.or_else(|| self.original_destination_cid.as_ref())
.unwrap()
.clone(),
),
@ -1585,35 +1495,29 @@ impl Connection {
debug_assert_eq!(packet.packet_type(), PacketType::Initial);
self.remote_initial_source_cid = Some(ConnectionId::from(packet.scid()));
let got_version = if self.role == Role::Server {
self.cid_manager
.add_odcid(self.original_destination_cid.as_ref().unwrap().clone());
if self.role == Role::Server {
// Record the client's selected CID so that it can be accepted until
// the client starts using a real connection ID.
let dcid = ConnectionId::from(packet.dcid());
self.original_destination_cid = Some(dcid.clone());
self.cid_manager.add_odcid(dcid);
// Make a path on which to run the handshake.
self.setup_handshake_path(path, now);
self.zero_rtt_state = match self.crypto.enable_0rtt(self.version, self.role) {
self.zero_rtt_state = match self.crypto.enable_0rtt(self.role) {
Ok(true) => {
qdebug!([self], "Accepted 0-RTT");
ZeroRttState::AcceptedServer
}
_ => ZeroRttState::Rejected,
};
// The server knows the final version if it has remote transport parameters.
self.tps.borrow().remote.is_some()
} else {
qdebug!([self], "Changing to use Server CID={}", packet.scid());
debug_assert!(path.borrow().is_primary());
path.borrow_mut().set_remote_cid(packet.scid());
// The client knows the final version if it processed a CRYPTO frame.
self.stats.borrow().frame_rx.crypto > 0
};
if got_version {
self.set_state(State::Handshaking);
} else {
self.set_state(State::WaitVersion);
}
self.set_state(State::Handshaking);
}
/// Migrate to the provided path.
@ -1743,7 +1647,6 @@ impl Connection {
let res = match &self.state {
State::Init
| State::WaitInitial
| State::WaitVersion
| State::Handshaking
| State::Connected
| State::Confirmed => {
@ -1773,7 +1676,7 @@ impl Connection {
encoder: Encoder,
tx: &CryptoDxState,
address_validation: &AddressValidationInfo,
version: Version,
quic_version: QuicVersion,
grease_quic_bit: bool,
) -> (PacketType, PacketBuilder) {
let pt = PacketType::from(cspace);
@ -1788,7 +1691,13 @@ impl Connection {
path.local_cid(),
);
PacketBuilder::long(encoder, pt, version, path.remote_cid(), path.local_cid())
PacketBuilder::long(
encoder,
pt,
quic_version,
path.remote_cid(),
path.local_cid(),
)
};
if builder.remaining() > 0 {
builder.scramble(grease_quic_bit);
@ -1839,12 +1748,11 @@ impl Connection {
let grease_quic_bit = self.can_grease_quic_bit();
let version = self.version();
for space in PacketNumberSpace::iter() {
let (cspace, tx) =
if let Some(crypto) = self.crypto.states.select_tx_mut(self.version, *space) {
crypto
} else {
continue;
};
let (cspace, tx) = if let Some(crypto) = self.crypto.states.select_tx_mut(*space) {
crypto
} else {
continue;
};
let path = close.path().borrow();
let (_, mut builder) = Self::build_packet_header(
@ -1977,18 +1885,13 @@ impl Connection {
tokens: &mut Vec<RecoveryToken>,
now: Instant,
) -> bool {
let untracked = self.received_untracked && !self.state.connected();
self.received_untracked = false;
// Anything written after an ACK already elicits acknowledgment.
// If we need to probe and nothing has been written, send a PING.
if builder.len() > ack_end {
return true;
}
let probe = if untracked && builder.packet_empty() || force_probe {
// If we received an untracked packet and we aren't probing already
// or the PTO timer fired: probe.
let probe = if force_probe {
// The packet might be empty, but we need to probe.
true
} else {
let pto = path.borrow().rtt().pto(PacketNumberSpace::ApplicationData);
@ -2109,12 +2012,11 @@ impl Connection {
let mut encoder = Encoder::with_capacity(profile.limit());
for space in PacketNumberSpace::iter() {
// Ensure we have tx crypto state for this epoch, or skip it.
let (cspace, tx) =
if let Some(crypto) = self.crypto.states.select_tx_mut(self.version, *space) {
crypto
} else {
continue;
};
let (cspace, tx) = if let Some(crypto) = self.crypto.states.select_tx_mut(*space) {
crypto
} else {
continue;
};
let header_start = encoder.len();
let (pt, mut builder) = Self::build_packet_header(
@ -2157,25 +2059,17 @@ impl Connection {
continue;
}
dump_packet(
self,
path,
"TX ->",
pt,
pn,
&builder.as_ref()[payload_start..],
);
dump_packet(self, path, "TX ->", pt, pn, &builder[payload_start..]);
qlog::packet_sent(
&mut self.qlog,
pt,
pn,
builder.len() - header_start + aead_expansion,
&builder.as_ref()[payload_start..],
&builder[payload_start..],
);
self.stats.borrow_mut().packets_tx += 1;
let tx = self.crypto.states.tx_mut(self.version, cspace).unwrap();
encoder = builder.build(tx)?;
encoder = builder.build(self.crypto.states.tx_mut(cspace).unwrap())?;
debug_assert!(encoder.len() <= mtu);
self.crypto.states.auto_update()?;
@ -2205,13 +2099,14 @@ impl Connection {
self.loss_recovery.on_packet_sent(path, sent);
}
if *space == PacketNumberSpace::Handshake
&& self.role == Role::Server
&& self.state == State::Confirmed
{
// We could discard handshake keys in set_state,
// but wait until after sending an ACK.
self.discard_keys(PacketNumberSpace::Handshake, now);
if *space == PacketNumberSpace::Handshake {
if self.role == Role::Client {
// Client can send Handshake packets -> discard Initial keys and states
self.discard_keys(PacketNumberSpace::Initial, now);
} else if self.state == State::Confirmed {
// We could discard handshake keys in set_state, but wait until after sending an ACK.
self.discard_keys(PacketNumberSpace::Handshake, now);
}
}
}
@ -2255,9 +2150,9 @@ impl Connection {
debug_assert_eq!(self.role, Role::Client);
qlog::client_connection_started(&mut self.qlog, &self.paths.primary());
self.handshake(now, self.version, PacketNumberSpace::Initial, None)?;
self.handshake(now, PacketNumberSpace::Initial, None)?;
self.set_state(State::WaitInitial);
self.zero_rtt_state = if self.crypto.enable_0rtt(self.version, self.role)? {
self.zero_rtt_state = if self.crypto.enable_0rtt(self.role)? {
qdebug!([self], "Enabled 0-RTT");
ZeroRttState::Sending
} else {
@ -2310,7 +2205,6 @@ impl Connection {
/// Process the final set of transport parameters.
fn process_tps(&mut self) -> Res<()> {
self.validate_cids()?;
self.validate_versions()?;
{
let tps = self.tps.borrow();
let remote = tps.remote.as_ref().unwrap();
@ -2421,91 +2315,9 @@ impl Connection {
Ok(())
}
/// Validate the `version_negotiation` transport parameter from the peer.
fn validate_versions(&mut self) -> Res<()> {
let tph = self.tps.borrow();
let remote_tps = tph.remote.as_ref().unwrap();
// `current` and `other` are the value from the peer's transport parameters.
// We're checking that these match our expectations.
if let Some((current, other)) = remote_tps.get_versions() {
qtrace!(
[self],
"validate_versions: current={:x} chosen={:x} other={:x?}",
self.version.wire_version(),
current,
other,
);
if self.role == Role::Server {
// 1. A server acts on transport parameters, with validation
// of `current` happening in the transport parameter handler.
// All we need to do is confirm that the transport parameter
// was provided.
Ok(())
} else if self.version().wire_version() != current {
qinfo!([self], "validate_versions: current version mismatch");
Err(Error::VersionNegotiation)
} else if self
.conn_params
.get_versions()
.initial()
.is_compatible(self.version)
{
// 2. The current version is compatible with what we attempted.
// That's a compatible upgrade and that's OK.
Ok(())
} else {
// 3. The initial version we attempted isn't compatible. Check that
// the one we would have chosen is compatible with this one.
let mut all_versions = other.to_owned();
all_versions.push(current);
if self
.conn_params
.get_versions()
.preferred(&all_versions)
.ok_or(Error::VersionNegotiation)?
.is_compatible(self.version)
{
Ok(())
} else {
qinfo!([self], "validate_versions: failed");
Err(Error::VersionNegotiation)
}
}
} else if self.version != Version::Version1 && !self.version.is_draft() {
qinfo!([self], "validate_versions: missing extension");
Err(Error::VersionNegotiation)
} else {
Ok(())
}
}
fn confirm_version(&mut self, v: Version) {
if self.version != v {
qinfo!([self], "Compatible upgrade {:?} ==> {:?}", self.version, v);
}
self.crypto.confirm_version(v);
self.version = v;
}
fn compatible_upgrade(&mut self, packet_version: Version) {
if !matches!(self.state, State::WaitInitial | State::WaitVersion) {
return;
}
if self.role == Role::Client {
self.confirm_version(packet_version);
} else if self.tps.borrow().remote.is_some() {
let version = self.tps.borrow().version();
let dcid = self.original_destination_cid.as_ref().unwrap();
self.crypto.states.init_server(version, dcid);
self.confirm_version(version);
}
}
fn handshake(
&mut self,
now: Instant,
packet_version: Version,
space: PacketNumberSpace,
data: Option<&[u8]>,
) -> Res<()> {
@ -2529,19 +2341,13 @@ impl Connection {
}
// There is a chance that this could be called less often, but getting the
// conditions right is a little tricky, so call whenever CRYPTO data is used.
// conditions right is a little tricky, so call it on every CRYPTO frame.
if try_update {
self.compatible_upgrade(packet_version);
// We have transport parameters, it's go time.
if self.tps.borrow().remote.is_some() {
self.set_initial_limits();
}
if self.crypto.install_keys(self.role)? {
if self.role == Role::Client {
// We won't acknowledge Initial packets as a result of this, but the
// server can rely on implicit acknowledgment.
self.discard_keys(PacketNumberSpace::Initial, now);
}
self.saved_datagrams.make_available(CryptoSpace::Handshake);
}
}
@ -2552,17 +2358,16 @@ impl Connection {
fn input_frame(
&mut self,
path: &PathRef,
packet_version: Version,
packet_type: PacketType,
ptype: PacketType,
frame: Frame,
now: Instant,
) -> Res<()> {
if !frame.is_allowed(packet_type) {
qinfo!("frame not allowed: {:?} {:?}", frame, packet_type);
if !frame.is_allowed(ptype) {
qinfo!("frame not allowed: {:?} {:?}", frame, ptype);
return Err(Error::ProtocolViolation);
}
self.stats.borrow_mut().frame_rx.all += 1;
let space = PacketNumberSpace::from(packet_type);
let space = PacketNumberSpace::from(ptype);
if frame.is_stream() {
return self
.streams
@ -2607,7 +2412,7 @@ impl Connection {
let mut buf = Vec::new();
let read = self.crypto.streams.read_to_end(space, &mut buf);
qdebug!("Read {} bytes", read);
self.handshake(now, packet_version, space, Some(&buf))?;
self.handshake(now, space, Some(&buf))?;
self.create_resumption_token(now);
} else {
// If we get a useless CRYPTO frame send outstanding CRYPTO frames again.
@ -2811,14 +2616,14 @@ impl Connection {
}
/// When the server rejects 0-RTT we need to drop a bunch of stuff.
fn client_0rtt_rejected(&mut self, now: Instant) {
fn client_0rtt_rejected(&mut self) {
if !matches!(self.zero_rtt_state, ZeroRttState::Sending) {
return;
}
qdebug!([self], "0-RTT rejected");
// Tell 0-RTT packets that they were "lost".
let dropped = self.loss_recovery.drop_0rtt(&self.paths.primary(), now);
let dropped = self.loss_recovery.drop_0rtt(&self.paths.primary());
self.handle_lost_packets(&dropped);
self.streams.zero_rtt_rejected();
@ -2846,15 +2651,14 @@ impl Connection {
self.zero_rtt_state = if self.crypto.tls.info().unwrap().early_data_accepted() {
ZeroRttState::AcceptedClient
} else {
self.client_0rtt_rejected(now);
self.client_0rtt_rejected();
ZeroRttState::Rejected
};
}
// Setting application keys has to occur after 0-RTT rejection.
let pto = self.pto();
self.crypto
.install_application_keys(self.version, now + pto)?;
self.crypto.install_application_keys(now + pto)?;
self.process_tps()?;
self.set_state(State::Connected);
self.create_resumption_token(now);
@ -3040,7 +2844,7 @@ impl Connection {
let (cspace, tx) = if let Some(crypto) = self
.crypto
.states
.select_tx(self.version, PacketNumberSpace::ApplicationData)
.select_tx(PacketNumberSpace::ApplicationData)
{
crypto
} else {

View File

@ -11,8 +11,7 @@ use crate::rtt::GRANULARITY;
use crate::stream_id::StreamType;
use crate::tparams::{self, PreferredAddress, TransportParameter, TransportParametersHandler};
use crate::tracking::DEFAULT_ACK_DELAY;
use crate::version::{Version, VersionConfig};
use crate::{CongestionControlAlgorithm, Res};
use crate::{CongestionControlAlgorithm, QuicVersion, Res};
use std::cmp::max;
use std::convert::TryFrom;
use std::time::Duration;
@ -43,9 +42,9 @@ pub enum PreferredAddressConfig {
/// ConnectionParameters use for setting intitial value for QUIC parameters.
/// This collects configuration like initial limits, protocol version, and
/// congestion control algorithm.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy)]
pub struct ConnectionParameters {
versions: VersionConfig,
quic_version: QuicVersion,
cc_algorithm: CongestionControlAlgorithm,
/// Initial connection-level flow control limit.
max_data: u64,
@ -78,7 +77,7 @@ pub struct ConnectionParameters {
impl Default for ConnectionParameters {
fn default() -> Self {
Self {
versions: VersionConfig::default(),
quic_version: QuicVersion::default(),
cc_algorithm: CongestionControlAlgorithm::NewReno,
max_data: LOCAL_MAX_DATA,
max_stream_data_bidi_remote: u64::try_from(RECV_BUFFER_SIZE).unwrap(),
@ -98,20 +97,12 @@ impl Default for ConnectionParameters {
}
impl ConnectionParameters {
pub fn get_versions(&self) -> &VersionConfig {
&self.versions
pub fn get_quic_version(&self) -> QuicVersion {
self.quic_version
}
pub(crate) fn get_versions_mut(&mut self) -> &mut VersionConfig {
&mut self.versions
}
/// Describe the initial version that should be attempted and all the
/// versions that should be enabled. This list should contain the initial
/// version and be in order of preference, with more preferred versions
/// before less preferred.
pub fn versions(mut self, initial: Version, all: Vec<Version>) -> Self {
self.versions = VersionConfig::new(initial, all);
pub fn quic_version(mut self, v: QuicVersion) -> Self {
self.quic_version = v;
self
}
@ -287,7 +278,7 @@ impl ConnectionParameters {
role: Role,
cid_manager: &mut ConnectionIdManager,
) -> Res<TransportParametersHandler> {
let mut tps = TransportParametersHandler::new(role, self.versions.clone());
let mut tps = TransportParametersHandler::default();
// default parameters
tps.local.set_integer(
tparams::ACTIVE_CONNECTION_ID_LIMIT,

View File

@ -22,17 +22,8 @@ use crate::{ConnectionError, Error, Res};
#[derive(Clone, Debug, PartialEq, Eq)]
/// The state of the Connection.
pub enum State {
/// A newly created connection.
Init,
/// Waiting for the first Initial packet.
WaitInitial,
/// Waiting to confirm which version was selected.
/// For a client, this is confirmed when a CRYPTO frame is received;
/// the version of the packet determines the version.
/// For a server, this is confirmed when transport parameters are
/// received and processed.
WaitVersion,
/// Exchanging Handshake packets.
Handshaking,
Connected,
Confirmed,
@ -90,8 +81,6 @@ impl Ord for State {
(_, Self::Init) => Ordering::Greater,
(Self::WaitInitial, _) => Ordering::Less,
(_, Self::WaitInitial) => Ordering::Greater,
(Self::WaitVersion, _) => Ordering::Less,
(_, Self::WaitVersion) => Ordering::Greater,
(Self::Handshaking, _) => Ordering::Less,
(_, Self::Handshaking) => Ordering::Greater,
(Self::Connected, _) => Ordering::Less,

View File

@ -7,8 +7,8 @@
use super::super::{Connection, Output, State};
use super::{
assert_error, connect, connect_force_idle, connect_with_rtt, default_client, default_server,
get_tokens, handshake, maybe_authenticate, resumed_server, send_something,
CountingConnectionIdGenerator, AT_LEAST_PTO, DEFAULT_RTT, DEFAULT_STREAM_DATA,
get_tokens, handshake, maybe_authenticate, send_something, CountingConnectionIdGenerator,
AT_LEAST_PTO, DEFAULT_RTT, DEFAULT_STREAM_DATA,
};
use crate::connection::AddressValidation;
use crate::events::ConnectionEvent;
@ -17,7 +17,8 @@ use crate::server::ValidateAddress;
use crate::tparams::{TransportParameter, MIN_ACK_DELAY};
use crate::tracking::DEFAULT_ACK_DELAY;
use crate::{
ConnectionError, ConnectionParameters, EmptyConnectionIdGenerator, Error, StreamType, Version,
ConnectionError, ConnectionParameters, EmptyConnectionIdGenerator, Error, QuicVersion,
StreamType,
};
use neqo_common::{event::Provider, qdebug, Datagram};
@ -355,7 +356,7 @@ fn reorder_05rtt_with_0rtt() {
let token = get_tokens(&mut client).pop().unwrap();
let mut client = default_client();
client.enable_resumption(now, token).unwrap();
let mut server = resumed_server(&client);
let mut server = default_server();
// Send ClientHello and some 0-RTT.
let c1 = send_something(&mut client, now);
@ -397,9 +398,7 @@ fn reorder_05rtt_with_0rtt() {
now += RTT / 2;
server.process_input(c4.unwrap(), now);
assert_eq!(*server.state(), State::Confirmed);
// Don't check server RTT as it will be massively inflated by a
// poor initial estimate received when the server dropped the
// Initial packet number space.
assert_eq!(server.paths.rtt(), RTT);
}
/// Test that a server that coalesces 0.5 RTT with handshake packets
@ -523,9 +522,7 @@ fn reorder_handshake() {
now += RTT / 2;
let s3 = server.process(c3, now).dgram();
assert_eq!(*server.state(), State::Confirmed);
// Don't check server RTT estimate as it will be inflated due to
// it making a guess based on retransmissions when it dropped
// the Initial packet number space.
assert_eq!(server.paths.rtt(), RTT);
now += RTT / 2;
client.process_input(s3.unwrap(), now);
@ -569,8 +566,9 @@ fn reorder_1rtt() {
now += RTT / 2;
let s2 = server.process(c2, now).dgram();
// The server has now received those packets, and saved them.
// The two additional are a Handshake and a 1-RTT (w/ NEW_CONNECTION_ID).
assert_eq!(server.stats().packets_rx, PACKETS * 2 + 4);
// The three additional are: an Initial ACK, a Handshake,
// and a 1-RTT (containing NEW_CONNECTION_ID).
assert_eq!(server.stats().packets_rx, PACKETS * 2 + 5);
assert_eq!(server.stats().saved_datagrams, PACKETS);
assert_eq!(server.stats().dropped_rx, 1);
assert_eq!(*server.state(), State::Confirmed);
@ -716,36 +714,51 @@ fn extra_initial_invalid_cid() {
assert!(nothing.is_none());
}
#[test]
fn connect_one_version() {
fn connect_v(version: Version) {
fixture_init();
let mut client = Connection::new_client(
test_fixture::DEFAULT_SERVER_NAME,
test_fixture::DEFAULT_ALPN,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
addr(),
addr(),
ConnectionParameters::default().versions(version, vec![version]),
now(),
)
.unwrap();
let mut server = Connection::new_server(
test_fixture::DEFAULT_KEYS,
test_fixture::DEFAULT_ALPN,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
ConnectionParameters::default().versions(version, vec![version]),
)
.unwrap();
connect_force_idle(&mut client, &mut server);
assert_eq!(client.version(), version);
assert_eq!(server.version(), version);
}
fn connect_version(version: QuicVersion) {
fixture_init();
let mut client = Connection::new_client(
test_fixture::DEFAULT_SERVER_NAME,
test_fixture::DEFAULT_ALPN,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
addr(),
addr(),
ConnectionParameters::default().quic_version(version),
now(),
)
.unwrap();
let mut server = Connection::new_server(
test_fixture::DEFAULT_KEYS,
test_fixture::DEFAULT_ALPN,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
ConnectionParameters::default().quic_version(version),
)
.unwrap();
connect_force_idle(&mut client, &mut server);
}
for v in Version::all() {
println!("Connecting with {:?}", v);
connect_v(v);
}
#[test]
fn connect_v1() {
connect_version(QuicVersion::Version1);
}
#[test]
fn connect_29() {
connect_version(QuicVersion::Draft29);
}
#[test]
fn connect_30() {
connect_version(QuicVersion::Draft30);
}
#[test]
fn connect_31() {
connect_version(QuicVersion::Draft31);
}
#[test]
fn connect_32() {
connect_version(QuicVersion::Draft32);
}
#[test]
@ -784,9 +797,9 @@ fn anti_amplification() {
let ack = client.process(Some(s_init3), now).dgram().unwrap();
assert!(!maybe_authenticate(&mut client)); // No need yet.
// The client sends a padded datagram, with just ACK for Handshake.
assert_eq!(client.stats().frame_tx.ack, ack_count + 1);
assert_eq!(client.stats().frame_tx.all, frame_count + 1);
// The client sends a padded datagram, with just ACK for Initial + Handshake.
assert_eq!(client.stats().frame_tx.ack, ack_count + 2);
assert_eq!(client.stats().frame_tx.all, frame_count + 2);
assert_ne!(ack.len(), PATH_MTU_V6); // Not padded (it includes Handshake).
now += DEFAULT_RTT / 2;
@ -1015,115 +1028,3 @@ fn bad_min_ack_delay() {
)))
);
}
/// Ensure that the client probes correctly if it only receives Initial packets
/// from the server.
#[test]
fn only_server_initial() {
let mut server = default_server();
let mut client = default_client();
let mut now = now();
let client_dgram = client.process_output(now).dgram();
// Now fetch two flights of messages from the server.
let server_dgram1 = server.process(client_dgram, now).dgram();
let server_dgram2 = server.process_output(now + AT_LEAST_PTO).dgram();
// Only pass on the Initial from the first. We should get a Handshake in return.
let (initial, handshake) = split_datagram(&server_dgram1.unwrap());
assert!(handshake.is_some());
// The client will not acknowledge the Initial as it discards keys.
// It sends a Handshake probe instead, containing just a PING frame.
assert_eq!(client.stats().frame_tx.ping, 0);
let probe = client.process(Some(initial), now).dgram();
assertions::assert_handshake(&probe.unwrap());
assert_eq!(client.stats().dropped_rx, 0);
assert_eq!(client.stats().frame_tx.ping, 1);
let (initial, handshake) = split_datagram(&server_dgram2.unwrap());
assert!(handshake.is_some());
// The same happens after a PTO, even though the client will discard the Initial packet.
now += AT_LEAST_PTO;
assert_eq!(client.stats().frame_tx.ping, 1);
let discarded = client.stats().dropped_rx;
let probe = client.process(Some(initial), now).dgram();
assertions::assert_handshake(&probe.unwrap());
assert_eq!(client.stats().frame_tx.ping, 2);
assert_eq!(client.stats().dropped_rx, discarded + 1);
// Pass the Handshake packet and complete the handshake.
client.process_input(handshake.unwrap(), now);
maybe_authenticate(&mut client);
let dgram = client.process_output(now).dgram();
let dgram = server.process(dgram, now).dgram();
client.process_input(dgram.unwrap(), now);
assert_eq!(*client.state(), State::Confirmed);
assert_eq!(*server.state(), State::Confirmed);
}
// Collect a few spare Initial packets as the handshake is exchanged.
// Later, replay those packets to see if they result in additional probes; they should not.
#[test]
fn no_extra_probes_after_confirmed() {
let mut server = default_server();
let mut client = default_client();
let mut now = now();
// First, collect a client Initial.
let spare_initial = client.process_output(now).dgram();
assert!(spare_initial.is_some());
// Collect ANOTHER client Initial.
now += AT_LEAST_PTO;
let dgram = client.process_output(now).dgram();
let (replay_initial, _) = split_datagram(dgram.as_ref().unwrap());
// Finally, run the handshake.
now += AT_LEAST_PTO * 2;
let dgram = client.process_output(now).dgram();
let dgram = server.process(dgram, now).dgram();
// The server should have dropped the Initial keys now, so passing in the Initial
// should elicit a retransmit rather than having it completely ignored.
let spare_handshake = server.process(Some(replay_initial), now).dgram();
assert!(spare_handshake.is_some());
client.process_input(dgram.unwrap(), now);
maybe_authenticate(&mut client);
let dgram = client.process_output(now).dgram();
let dgram = server.process(dgram, now).dgram();
client.process_input(dgram.unwrap(), now);
assert_eq!(*client.state(), State::Confirmed);
assert_eq!(*server.state(), State::Confirmed);
let probe = server.process(spare_initial, now).dgram();
assert!(probe.is_none());
let probe = client.process(spare_handshake, now).dgram();
assert!(probe.is_none());
}
#[test]
fn implicit_rtt_server() {
const RTT: Duration = Duration::from_secs(2);
let mut server = default_server();
let mut client = default_client();
let mut now = now();
let dgram = client.process_output(now).dgram();
now += RTT / 2;
let dgram = server.process(dgram, now).dgram();
now += RTT / 2;
let dgram = client.process(dgram, now).dgram();
assertions::assert_handshake(dgram.as_ref().unwrap());
now += RTT / 2;
server.process_input(dgram.unwrap(), now);
// The server doesn't receive any acknowledgments, but it can infer
// an RTT estimate from having discarded the Initial packet number space.
assert_eq!(server.stats().rtt, RTT);
}

View File

@ -18,19 +18,13 @@ use neqo_common::{qdebug, Datagram};
use std::mem;
use test_fixture::{self, now};
fn check_discarded(
peer: &mut Connection,
pkt: Datagram,
response: bool,
dropped: usize,
dups: usize,
) {
fn check_discarded(peer: &mut Connection, pkt: Datagram, dropped: usize, dups: usize) {
// Make sure to flush any saved datagrams before doing this.
mem::drop(peer.process_output(now()));
let before = peer.stats();
let out = peer.process(Some(pkt), now());
assert_eq!(out.as_dgram_ref().is_some(), response);
assert!(out.as_dgram_ref().is_none());
let after = peer.stats();
assert_eq!(dropped, after.dropped_rx - before.dropped_rx);
assert_eq!(dups, after.dups_rx - before.dups_rx);
@ -66,12 +60,11 @@ fn discarded_initial_keys() {
let out = client.process(init_pkt_s.clone(), now()).dgram();
assert!(out.is_some());
// The client has received a handshake packet. It will remove the Initial keys.
// The client has received handshake packet. It will remove the Initial keys.
// We will check this by processing init_pkt_s a second time.
// The initial packet should be dropped. The packet contains a Handshake packet as well, which
// will be marked as dup. And it will contain padding, which will be "dropped".
// The client will generate a Handshake packet here to avoid stalling.
check_discarded(&mut client, init_pkt_s.unwrap(), true, 2, 1);
check_discarded(&mut client, init_pkt_s.unwrap(), 2, 1);
assert!(maybe_authenticate(&mut client));
@ -79,7 +72,7 @@ fn discarded_initial_keys() {
// packet from the client.
// We will check this by processing init_pkt_c a second time.
// The dropped packet is padding. The Initial packet has been mark dup.
check_discarded(&mut server, init_pkt_c.clone().unwrap(), false, 1, 1);
check_discarded(&mut server, init_pkt_c.clone().unwrap(), 1, 1);
qdebug!("---- client: SH..FIN -> FIN");
let out = client.process(None, now()).dgram();
@ -94,7 +87,7 @@ fn discarded_initial_keys() {
// We will check this by processing init_pkt_c a third time.
// The Initial packet has been dropped and padding that follows it.
// There is no dups, everything has been dropped.
check_discarded(&mut server, init_pkt_c.unwrap(), false, 1, 0);
check_discarded(&mut server, init_pkt_c.unwrap(), 1, 0);
}
#[test]
@ -207,7 +200,7 @@ fn key_update_consecutive() {
// However, as the server didn't wait long enough to update again, the
// client hasn't rotated its keys, so the packet gets dropped.
check_discarded(&mut client, dgram, false, 1, 0);
check_discarded(&mut client, dgram, 1, 0);
}
// Key updates can't be initiated too early.

View File

@ -16,7 +16,6 @@ use crate::recovery::ACK_ONLY_SIZE_LIMIT;
use crate::stats::{FrameStats, Stats, MAX_PTO_COUNTS};
use crate::{
ConnectionIdDecoder, ConnectionIdGenerator, ConnectionParameters, Error, StreamId, StreamType,
Version,
};
use std::cell::RefCell;
@ -129,9 +128,6 @@ pub fn new_server(params: ConnectionParameters) -> Connection {
pub fn default_server() -> Connection {
new_server(ConnectionParameters::default())
}
pub fn resumed_server(client: &Connection) -> Connection {
new_server(ConnectionParameters::default().versions(client.version(), Version::all()))
}
/// If state is `AuthenticationNeeded` call `authenticated()`. This function will
/// consume all outstanding events on the connection.
@ -215,10 +211,10 @@ fn connect(client: &mut Connection, server: &mut Connection) {
connect_with_rtt(client, server, now(), Duration::new(0, 0));
}
fn assert_error(c: &Connection, expected: &ConnectionError) {
fn assert_error(c: &Connection, err: &ConnectionError) {
match c.state() {
State::Closing { error, .. } | State::Draining { error, .. } | State::Closed(error) => {
assert_eq!(*error, *expected, "{} error mismatch", c);
assert_eq!(*error, *err);
}
_ => panic!("bad state {:?}", c.state()),
}

View File

@ -6,10 +6,9 @@
use super::{
connect, connect_with_rtt, default_client, default_server, exchange_ticket, get_tokens,
new_client, resumed_server, send_something, AT_LEAST_PTO,
send_something, AT_LEAST_PTO,
};
use crate::addr_valid::{AddressValidation, ValidateAddress};
use crate::{ConnectionParameters, Error, Version};
use std::cell::RefCell;
use std::mem;
@ -28,7 +27,7 @@ fn resume() {
client
.enable_resumption(now(), token)
.expect("should set token");
let mut server = resumed_server(&client);
let mut server = default_server();
connect(&mut client, &mut server);
assert!(client.tls_info().unwrap().resumed());
assert!(server.tls_info().unwrap().resumed());
@ -59,13 +58,13 @@ fn remember_smoothed_rtt() {
let token = get_tokens(&mut client).pop().unwrap();
let mut client = default_client();
let mut server = default_server();
client.enable_resumption(now, token).unwrap();
assert_eq!(
client.paths.rtt(),
RTT1,
"client should remember previous RTT"
);
let mut server = resumed_server(&client);
connect_with_rtt(&mut client, &mut server, now, RTT2);
assert_eq!(
@ -90,7 +89,7 @@ fn address_validation_token_resume() {
let token = exchange_ticket(&mut client, &mut server, now);
let mut client = default_client();
client.enable_resumption(now, token).unwrap();
let mut server = resumed_server(&client);
let mut server = default_server();
// Grab an Initial packet from the client.
let dgram = client.process(None, now).dgram();
@ -194,53 +193,3 @@ fn take_token() {
let token = client.take_resumption_token(now()).unwrap();
can_resume(&token, false);
}
/// If a version is selected and subsequently disabled, resumption fails.
#[test]
fn resume_disabled_version() {
let mut client = new_client(
ConnectionParameters::default().versions(Version::Version1, vec![Version::Version1]),
);
let mut server = default_server();
connect(&mut client, &mut server);
let token = exchange_ticket(&mut client, &mut server, now());
let mut client = new_client(
ConnectionParameters::default().versions(Version::Version2, vec![Version::Version2]),
);
assert_eq!(
client.enable_resumption(now(), token).unwrap_err(),
Error::DisabledVersion
);
}
/// It's not possible to resume once a packet has been sent.
#[test]
fn resume_after_packet() {
let mut client = default_client();
let mut server = default_server();
connect(&mut client, &mut server);
let token = exchange_ticket(&mut client, &mut server, now());
let mut client = default_client();
mem::drop(client.process_output(now()).dgram().unwrap());
assert_eq!(
client.enable_resumption(now(), token).unwrap_err(),
Error::ConnectionState
);
}
/// It's not possible to resume at the server.
#[test]
fn resume_server() {
let mut client = default_client();
let mut server = default_server();
connect(&mut client, &mut server);
let token = exchange_ticket(&mut client, &mut server, now());
let mut server = default_server();
assert_eq!(
server.enable_resumption(now(), token).unwrap_err(),
Error::ConnectionState
);
}

View File

@ -4,19 +4,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::super::{ConnectionError, ConnectionEvent, Output, State, ZeroRttState};
use super::{
connect, connect_fail, default_client, default_server, exchange_ticket, new_client, new_server,
send_something,
};
use super::super::{ConnectionError, Output, State};
use super::{default_client, default_server};
use crate::packet::PACKET_BIT_LONG;
use crate::tparams::{self, TransportParameter};
use crate::{ConnectionParameters, Error, Version};
use crate::{Error, QuicVersion};
use neqo_common::{event::Provider, Datagram, Decoder, Encoder};
use neqo_common::{Datagram, Decoder, Encoder};
use std::mem;
use std::time::Duration;
use test_fixture::{self, addr, assertions, now};
use test_fixture::{self, addr, now};
// The expected PTO duration after the first Initial is sent.
const INITIAL_PTO: Duration = Duration::from_millis(300);
@ -62,8 +58,8 @@ fn create_vn(initial_pkt: &[u8], versions: &[u32]) -> Vec<u8> {
let mut encoder = Encoder::default();
encoder.encode_byte(PACKET_BIT_LONG);
encoder.encode(&[0; 4]); // Zero version == VN.
encoder.encode_vec(1, src_cid);
encoder.encode_vec(1, dst_cid);
encoder.encode_vec(1, src_cid);
for v in versions {
encoder.encode_uint(4, *v);
@ -83,7 +79,7 @@ fn version_negotiation_current_version() {
let vn = create_vn(
&initial_pkt,
&[0x1a1a_1a1a, Version::default().wire_version()],
&[0x1a1a_1a1a, QuicVersion::default().as_u32()],
);
let dgram = Datagram::new(addr(), addr(), vn);
@ -93,25 +89,6 @@ fn version_negotiation_current_version() {
assert_eq!(1, client.stats().dropped_rx);
}
#[test]
fn version_negotiation_version0() {
let mut client = default_client();
// Start the handshake.
let initial_pkt = client
.process(None, now())
.dgram()
.expect("a datagram")
.to_vec();
let vn = create_vn(&initial_pkt, &[0, 0x1a1a_1a1a]);
let dgram = Datagram::new(addr(), addr(), vn);
let delay = client.process(Some(dgram), now()).callback();
assert_eq!(delay, INITIAL_PTO);
assert_eq!(*client.state(), State::WaitInitial);
assert_eq!(1, client.stats().dropped_rx);
}
#[test]
fn version_negotiation_only_reserved() {
let mut client = default_client();
@ -183,8 +160,11 @@ fn version_negotiation_not_supported() {
.to_vec();
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a, 0xff00_0001]);
let dgram = Datagram::new(addr(), addr(), vn);
assert_eq!(client.process(Some(dgram), now()), Output::None);
assert_eq!(
client.process(Some(Datagram::new(addr(), addr(), vn)), now(),),
Output::None
);
match client.state() {
State::Closed(err) => {
assert_eq!(*err, ConnectionError::Transport(Error::VersionNegotiation));
@ -197,14 +177,14 @@ fn version_negotiation_not_supported() {
fn version_negotiation_bad_cid() {
let mut client = default_client();
// Start the handshake.
let mut initial_pkt = client
let initial_pkt = client
.process(None, now())
.dgram()
.expect("a datagram")
.to_vec();
initial_pkt[6] ^= 0xc4;
let vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a, 0xff00_0001]);
let mut vn = create_vn(&initial_pkt, &[0x1a1a_1a1a, 0x2a2a_2a2a, 0xff00_0001]);
vn[6] ^= 0xc4;
let dgram = Datagram::new(addr(), addr(), vn);
let delay = client.process(Some(dgram), now()).callback();
@ -212,275 +192,3 @@ fn version_negotiation_bad_cid() {
assert_eq!(*client.state(), State::WaitInitial);
assert_eq!(1, client.stats().dropped_rx);
}
#[test]
fn compatible_upgrade() {
let mut client = default_client();
let mut server = default_server();
connect(&mut client, &mut server);
assert_eq!(client.version(), Version::Version2);
assert_eq!(server.version(), Version::Version2);
}
/// When the first packet from the client is gigantic, the server might generate acknowledgment packets in
/// version 1. Both client and server need to handle that gracefully.
#[test]
fn compatible_upgrade_large_initial() {
let params = ConnectionParameters::default().versions(
Version::Version1,
vec![Version::Version2, Version::Version1],
);
let mut client = new_client(params.clone());
client
.set_local_tparam(
0x0845_de37_00ac_a5f9,
TransportParameter::Bytes(vec![0; 2048]),
)
.unwrap();
let mut server = new_server(params);
// Client Initial should take 2 packets.
// Each should elicit a Version 1 ACK from the server.
let dgram = client.process_output(now()).dgram();
assert!(dgram.is_some());
let dgram = server.process(dgram, now()).dgram();
assert!(dgram.is_some());
// The following uses the Version from *outside* this crate.
assertions::assert_version(dgram.as_ref().unwrap(), Version::Version1.wire_version());
client.process_input(dgram.unwrap(), now());
connect(&mut client, &mut server);
assert_eq!(client.version(), Version::Version2);
assert_eq!(server.version(), Version::Version2);
// Only handshake padding is "dropped".
assert_eq!(client.stats().dropped_rx, 1);
assert_eq!(server.stats().dropped_rx, 1);
}
/// A server that supports versions 1 and 2 might prefer version 1 and that's OK.
/// This one starts with version 1 and stays there.
#[test]
fn compatible_no_upgrade() {
let mut client = new_client(ConnectionParameters::default().versions(
Version::Version1,
vec![Version::Version2, Version::Version1],
));
let mut server = new_server(ConnectionParameters::default().versions(
Version::Version1,
vec![Version::Version1, Version::Version2],
));
connect(&mut client, &mut server);
assert_eq!(client.version(), Version::Version1);
assert_eq!(server.version(), Version::Version1);
}
/// A server that supports versions 1 and 2 might prefer version 1 and that's OK.
/// This one starts with version 2 and downgrades to version 1.
#[test]
fn compatible_downgrade() {
let mut client = new_client(ConnectionParameters::default().versions(
Version::Version2,
vec![Version::Version2, Version::Version1],
));
let mut server = new_server(ConnectionParameters::default().versions(
Version::Version2,
vec![Version::Version1, Version::Version2],
));
connect(&mut client, &mut server);
assert_eq!(client.version(), Version::Version1);
assert_eq!(server.version(), Version::Version1);
}
/// Inject a Version Negotiation packet, which the client detects when it validates the
/// server `version_negotiation` transport parameter.
#[test]
fn version_negotiation_downgrade() {
const DOWNGRADE: Version = Version::Draft29;
let mut client = default_client();
// The server sets the current version in the transport parameter and
// protects Initial packets with the version in its configuration.
// When a server `Connection` is created by a `Server`, the configuration is set
// to match the version of the packet it first receives. This replicates that.
let mut server =
new_server(ConnectionParameters::default().versions(DOWNGRADE, Version::all()));
// Start the handshake and spoof a VN packet.
let initial = client.process_output(now()).dgram().unwrap();
let vn = create_vn(&initial, &[DOWNGRADE.wire_version()]);
let dgram = Datagram::new(addr(), addr(), vn);
client.process_input(dgram, now());
connect_fail(
&mut client,
&mut server,
Error::VersionNegotiation,
Error::PeerError(Error::VersionNegotiation.code()),
);
}
/// A server connection needs to be configured with the version that the client attempts.
/// Otherwise, it will object to the client transport parameters and not do anything.
#[test]
fn invalid_server_version() {
let mut client =
new_client(ConnectionParameters::default().versions(Version::Version1, Version::all()));
let mut server =
new_server(ConnectionParameters::default().versions(Version::Version2, Version::all()));
let dgram = client.process_output(now()).dgram();
server.process_input(dgram.unwrap(), now());
// One packet received.
assert_eq!(server.stats().packets_rx, 1);
// None dropped; the server will have decrypted it successfully.
assert_eq!(server.stats().dropped_rx, 0);
assert_eq!(server.stats().saved_datagrams, 0);
// The server effectively hasn't reacted here.
match server.state() {
State::Closed(err) => {
assert_eq!(*err, ConnectionError::Transport(Error::CryptoAlert(47)));
}
_ => panic!("invalid server state"),
}
}
#[test]
fn invalid_current_version_client() {
const OTHER_VERSION: Version = Version::Draft29;
let mut client = default_client();
let mut server = default_server();
assert_ne!(OTHER_VERSION, client.version());
client
.set_local_tparam(
tparams::VERSION_NEGOTIATION,
TransportParameter::Versions {
current: OTHER_VERSION.wire_version(),
other: Version::all()
.iter()
.copied()
.map(Version::wire_version)
.collect(),
},
)
.unwrap();
connect_fail(
&mut client,
&mut server,
Error::PeerError(Error::CryptoAlert(47).code()),
Error::CryptoAlert(47),
);
}
/// To test this, we need to disable compatible upgrade so that the server doesn't update
/// its transport parameters. Then, we can overwrite its transport parameters without
/// them being overwritten. Otherwise, it would be hard to find a window during which
/// the transport parameter can be modified.
#[test]
fn invalid_current_version_server() {
const OTHER_VERSION: Version = Version::Draft29;
let mut client = default_client();
let mut server = new_server(
ConnectionParameters::default().versions(Version::default(), vec![Version::default()]),
);
assert!(!Version::default().is_compatible(OTHER_VERSION));
server
.set_local_tparam(
tparams::VERSION_NEGOTIATION,
TransportParameter::Versions {
current: OTHER_VERSION.wire_version(),
other: vec![OTHER_VERSION.wire_version()],
},
)
.unwrap();
connect_fail(
&mut client,
&mut server,
Error::CryptoAlert(47),
Error::PeerError(Error::CryptoAlert(47).code()),
);
}
#[test]
fn no_compatible_version() {
const OTHER_VERSION: Version = Version::Draft29;
let mut client = default_client();
let mut server = default_server();
assert_ne!(OTHER_VERSION, client.version());
client
.set_local_tparam(
tparams::VERSION_NEGOTIATION,
TransportParameter::Versions {
current: Version::default().wire_version(),
other: vec![OTHER_VERSION.wire_version()],
},
)
.unwrap();
connect_fail(
&mut client,
&mut server,
Error::PeerError(Error::CryptoAlert(47).code()),
Error::CryptoAlert(47),
);
}
/// When a compatible upgrade chooses a different version, 0-RTT is rejected.
#[test]
fn compatible_upgrade_0rtt_rejected() {
// This is the baseline configuration where v1 is attempted and v2 preferred.
let prefer_v2 = ConnectionParameters::default().versions(
Version::Version1,
vec![Version::Version2, Version::Version1],
);
let mut client = new_client(prefer_v2.clone());
// The server will start with this so that the client resumes with v1.
let just_v1 =
ConnectionParameters::default().versions(Version::Version1, vec![Version::Version1]);
let mut server = new_server(just_v1);
connect(&mut client, &mut server);
assert_eq!(client.version(), Version::Version1);
let token = exchange_ticket(&mut client, &mut server, now());
// Now upgrade the server to the preferred configuration.
let mut client = new_client(prefer_v2.clone());
let mut server = new_server(prefer_v2);
client.enable_resumption(now(), token).unwrap();
// Create a packet with 0-RTT from the client.
let initial = send_something(&mut client, now());
assertions::assert_version(&initial, Version::Version1.wire_version());
assertions::assert_coalesced_0rtt(&initial);
server.process_input(initial, now());
assert!(!server
.events()
.any(|e| matches!(e, ConnectionEvent::NewStream { .. })));
// Finalize the connection. Don't use connect() because it uses
// maybe_authenticate() too liberally and that eats the events we want to check.
let dgram = server.process_output(now()).dgram(); // ServerHello flight
let dgram = client.process(dgram, now()).dgram(); // Client Finished (note: no authentication)
let dgram = server.process(dgram, now()).dgram(); // HANDSHAKE_DONE
client.process_input(dgram.unwrap(), now());
assert!(matches!(client.state(), State::Confirmed));
assert!(matches!(server.state(), State::Confirmed));
assert!(client.events().any(|e| {
println!(" client event: {:?}", e);
matches!(e, ConnectionEvent::ZeroRttRejected)
}));
assert_eq!(client.zero_rtt_state(), ZeroRttState::Rejected);
}

View File

@ -6,11 +6,11 @@
use super::super::Connection;
use super::{
connect, default_client, default_server, exchange_ticket, new_server, resumed_server,
connect, default_client, default_server, exchange_ticket, new_server,
CountingConnectionIdGenerator,
};
use crate::events::ConnectionEvent;
use crate::{ConnectionParameters, Error, StreamType, Version};
use crate::{ConnectionParameters, Error, StreamType};
use neqo_common::event::Provider;
use neqo_crypto::{AllowZeroRtt, AntiReplay};
@ -31,7 +31,7 @@ fn zero_rtt_negotiate() {
client
.enable_resumption(now(), token)
.expect("should set token");
let mut server = resumed_server(&client);
let mut server = default_server();
connect(&mut client, &mut server);
assert!(client.tls_info().unwrap().early_data_accepted());
assert!(server.tls_info().unwrap().early_data_accepted());
@ -48,7 +48,7 @@ fn zero_rtt_send_recv() {
client
.enable_resumption(now(), token)
.expect("should set token");
let mut server = resumed_server(&client);
let mut server = default_server();
// Send ClientHello.
let client_hs = client.process(None, now());
@ -93,7 +93,7 @@ fn zero_rtt_send_coalesce() {
client
.enable_resumption(now(), token)
.expect("should set token");
let mut server = resumed_server(&client);
let mut server = default_server();
// Write 0-RTT before generating any packets.
// This should result in a datagram that coalesces Initial and 0-RTT.
@ -140,7 +140,7 @@ fn zero_rtt_send_reject() {
test_fixture::DEFAULT_KEYS,
test_fixture::DEFAULT_ALPN,
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
ConnectionParameters::default().versions(client.version(), Version::all()),
ConnectionParameters::default(),
)
.unwrap();
// Using a freshly initialized anti-replay context
@ -221,8 +221,7 @@ fn zero_rtt_update_flow_control() {
let mut server = new_server(
ConnectionParameters::default()
.max_stream_data(StreamType::UniDi, true, HIGH)
.max_stream_data(StreamType::BiDi, true, HIGH)
.versions(client.version, Version::all()),
.max_stream_data(StreamType::BiDi, true, HIGH),
);
// Stream limits should be low for 0-RTT.

View File

@ -6,7 +6,6 @@
use std::cell::RefCell;
use std::cmp::{max, min};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::mem;
use std::ops::{Index, IndexMut, Range};
@ -23,15 +22,13 @@ use neqo_crypto::{
TLS_VERSION_1_3,
};
use crate::cid::ConnectionIdRef;
use crate::packet::{PacketBuilder, PacketNumber};
use crate::packet::{PacketBuilder, PacketNumber, QuicVersion};
use crate::recovery::RecoveryToken;
use crate::recv_stream::RxStreamOrderer;
use crate::send_stream::TxBuffer;
use crate::stats::FrameStats;
use crate::tparams::{TpZeroRttChecker, TransportParameters, TransportParametersHandler};
use crate::tracking::PacketNumberSpace;
use crate::version::Version;
use crate::{Error, Res};
const MAX_AUTH_TAG: usize = 32;
@ -51,8 +48,6 @@ thread_local!(pub(crate) static OVERWRITE_INVOCATIONS: RefCell<Option<PacketNumb
#[derive(Debug)]
pub struct Crypto {
version: Version,
protocols: Vec<String>,
pub(crate) tls: Agent,
pub(crate) streams: CryptoStreams,
pub(crate) states: CryptoStates,
@ -62,9 +57,9 @@ type TpHandler = Rc<RefCell<TransportParametersHandler>>;
impl Crypto {
pub fn new(
version: Version,
version: QuicVersion,
mut agent: Agent,
protocols: Vec<String>,
protocols: &[impl AsRef<str>],
tphandler: TpHandler,
) -> Res<Self> {
agent.set_version_range(TLS_VERSION_1_3, TLS_VERSION_1_3)?;
@ -73,7 +68,7 @@ impl Crypto {
TLS_AES_256_GCM_SHA384,
TLS_CHACHA20_POLY1305_SHA256,
])?;
agent.set_alpn(&protocols)?;
agent.set_alpn(protocols)?;
agent.disable_end_of_early_data()?;
// Always enable 0-RTT on the client, but the server needs
// more configuration passed to server_enable_0rtt.
@ -81,33 +76,20 @@ impl Crypto {
c.enable_0rtt()?;
}
let extension = match version {
Version::Version2 | Version::Version1 => 0x39,
Version::Draft29 | Version::Draft30 | Version::Draft31 | Version::Draft32 => 0xffa5,
QuicVersion::Version1 => 0x39,
QuicVersion::Draft29
| QuicVersion::Draft30
| QuicVersion::Draft31
| QuicVersion::Draft32 => 0xffa5,
};
agent.extension_handler(extension, tphandler)?;
Ok(Self {
version,
protocols,
tls: agent,
streams: Default::default(),
states: Default::default(),
})
}
/// Get the name of the server. (Only works for the client currently).
pub fn server_name(&self) -> Option<&str> {
if let Agent::Client(c) = &self.tls {
Some(c.server_name())
} else {
None
}
}
/// Get the set of enabled protocols.
pub fn protocols(&self) -> &[String] {
&self.protocols
}
pub fn server_enable_0rtt(
&mut self,
tphandler: TpHandler,
@ -192,7 +174,7 @@ impl Crypto {
}
/// Enable 0-RTT and return `true` if it is enabled successfully.
pub fn enable_0rtt(&mut self, version: Version, role: Role) -> Res<bool> {
pub fn enable_0rtt(&mut self, role: Role) -> Res<bool> {
let info = self.tls.preinfo()?;
// `info.early_data()` returns false for a server,
// so use `early_data_cipher()` to tell if 0-RTT is enabled.
@ -211,23 +193,16 @@ impl Crypto {
),
};
let secret = secret.ok_or(Error::InternalError(1))?;
self.states
.set_0rtt_keys(version, dir, &secret, cipher.unwrap());
self.states.set_0rtt_keys(dir, &secret, cipher.unwrap());
Ok(true)
}
/// Lock in a compatible upgrade.
pub fn confirm_version(&mut self, confirmed: Version) {
self.states.confirm_version(self.version, confirmed);
self.version = confirmed;
}
/// Returns true if new handshake keys were installed.
pub fn install_keys(&mut self, role: Role) -> Res<bool> {
if !self.tls.state().is_final() {
let installed_hs = self.install_handshake_keys()?;
if role == Role::Server {
self.maybe_install_application_write_key(self.version)?;
self.maybe_install_application_write_key()?;
}
Ok(installed_hs)
} else {
@ -253,22 +228,22 @@ impl Crypto {
}
.ok_or(Error::InternalError(3))?;
self.states
.set_handshake_keys(self.version, &write_secret, &read_secret, cipher);
.set_handshake_keys(&write_secret, &read_secret, cipher);
qdebug!([self], "Handshake keys installed");
Ok(true)
}
fn maybe_install_application_write_key(&mut self, version: Version) -> Res<()> {
fn maybe_install_application_write_key(&mut self) -> Res<()> {
qtrace!([self], "Attempt to install application write key");
if let Some(secret) = self.tls.write_secret(TLS_EPOCH_APPLICATION_DATA) {
self.states.set_application_write_key(version, secret)?;
self.states.set_application_write_key(secret)?;
qdebug!([self], "Application write key installed");
}
Ok(())
}
pub fn install_application_keys(&mut self, version: Version, expire_0rtt: Instant) -> Res<()> {
self.maybe_install_application_write_key(version)?;
pub fn install_application_keys(&mut self, expire_0rtt: Instant) -> Res<()> {
self.maybe_install_application_write_key()?;
// The write key might have been installed earlier, but it should
// always be installed now.
debug_assert!(self.states.app_write.is_some());
@ -277,7 +252,7 @@ impl Crypto {
.read_secret(TLS_EPOCH_APPLICATION_DATA)
.ok_or(Error::InternalError(4))?;
self.states
.set_application_read_key(version, read_secret, expire_0rtt)?;
.set_application_read_key(read_secret, expire_0rtt)?;
qdebug!([self], "application read keys installed");
Ok(())
}
@ -341,21 +316,19 @@ impl Crypto {
&mut self,
new_token: Option<&[u8]>,
tps: &TransportParameters,
version: Version,
rtt: u64,
) -> Option<ResumptionToken> {
if let Agent::Client(ref mut c) = self.tls {
if let Some(ref t) = c.resumption_token() {
qtrace!("TLS token {}", hex(t.as_ref()));
let mut enc = Encoder::default();
enc.encode_uint(4, version.wire_version());
enc.encode_varint(rtt);
enc.encode_vvec_with(|enc_inner| {
tps.encode(enc_inner);
});
enc.encode_vvec(new_token.unwrap_or(&[]));
enc.encode(t.as_ref());
qinfo!("resumption token {}", hex_snip_middle(enc.as_ref()));
qinfo!("resumption token {}", hex_snip_middle(&enc[..]));
Some(ResumptionToken::new(enc.into(), t.expiration_time()))
} else {
None
@ -388,9 +361,6 @@ pub enum CryptoDxDirection {
#[derive(Debug)]
pub struct CryptoDxState {
/// The QUIC version.
version: Version,
/// Whether packets protected with this state will be read or written.
direction: CryptoDxDirection,
/// The epoch of this crypto state. This initially tracks TLS epochs
/// via DTLS: 0 = initial, 1 = 0-RTT, 2 = handshake, 3 = application.
@ -413,26 +383,22 @@ pub struct CryptoDxState {
impl CryptoDxState {
#[allow(clippy::reversed_empty_ranges)] // To initialize an empty range.
pub fn new(
version: Version,
direction: CryptoDxDirection,
epoch: Epoch,
secret: &SymKey,
cipher: Cipher,
) -> Self {
qinfo!(
"Making {:?} {} CryptoDxState, v={:?} cipher={}",
"Making {:?} {} CryptoDxState, cipher={}",
direction,
epoch,
version,
cipher,
cipher
);
let hplabel = String::from(version.label_prefix()) + "hp";
Self {
version,
direction,
epoch: usize::from(epoch),
aead: Aead::new(TLS_VERSION_1_3, cipher, secret, version.label_prefix()).unwrap(),
hpkey: HpKey::extract(TLS_VERSION_1_3, cipher, secret, &hplabel).unwrap(),
aead: Aead::new(TLS_VERSION_1_3, cipher, secret, "quic ").unwrap(),
hpkey: HpKey::extract(TLS_VERSION_1_3, cipher, secret, "quic hp").unwrap(),
used_pn: 0..0,
min_pn: 0,
invocations: Self::limit(direction, cipher),
@ -440,13 +406,27 @@ impl CryptoDxState {
}
pub fn new_initial(
version: Version,
quic_version: QuicVersion,
direction: CryptoDxDirection,
label: &str,
dcid: &[u8],
) -> Self {
qtrace!("new_initial {:?} {}", version, ConnectionIdRef::from(dcid));
let salt = version.initial_salt();
const INITIAL_SALT_V1: &[u8] = &[
0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a,
];
const INITIAL_SALT_29_32: &[u8] = &[
0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61,
0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99,
];
qtrace!("new_initial for {:?}", quic_version);
let salt = match quic_version {
QuicVersion::Version1 => INITIAL_SALT_V1,
QuicVersion::Draft29
| QuicVersion::Draft30
| QuicVersion::Draft31
| QuicVersion::Draft32 => INITIAL_SALT_29_32,
};
let cipher = TLS_AES_128_GCM_SHA256;
let initial_secret = hkdf::extract(
TLS_VERSION_1_3,
@ -459,7 +439,7 @@ impl CryptoDxState {
let secret =
hkdf::expand_label(TLS_VERSION_1_3, cipher, &initial_secret, &[], label).unwrap();
Self::new(version, direction, TLS_EPOCH_INITIAL, &secret, cipher)
Self::new(direction, TLS_EPOCH_INITIAL, &secret, cipher)
}
/// Determine the confidentiality and integrity limits for the cipher.
@ -515,16 +495,9 @@ impl CryptoDxState {
Self::limit(CryptoDxDirection::Write, cipher)
};
Self {
version: self.version,
direction: self.direction,
epoch: self.epoch + 1,
aead: Aead::new(
TLS_VERSION_1_3,
cipher,
next_secret,
self.version.label_prefix(),
)
.unwrap(),
aead: Aead::new(TLS_VERSION_1_3, cipher, next_secret, "quic ").unwrap(),
hpkey: self.hpkey.clone(),
used_pn: pn..pn,
min_pn: pn,
@ -532,11 +505,6 @@ impl CryptoDxState {
}
}
#[must_use]
pub fn version(&self) -> Version {
self.version
}
#[must_use]
pub fn key_phase(&self) -> bool {
// Epoch 3 => 0, 4 => 1, 5 => 0, 6 => 1, ...
@ -549,7 +517,8 @@ impl CryptoDxState {
debug_assert_eq!(self.direction, prev.direction);
let next = prev.next_pn();
self.min_pn = next;
if self.used_pn.is_empty() {
// TODO(mt) use Range::is_empty() when available
if self.used_pn.start == self.used_pn.end {
self.used_pn = next..next;
Ok(())
} else if prev.used_pn.end > self.used_pn.start {
@ -669,7 +638,7 @@ impl CryptoDxState {
// This matches the value in packet.rs
const CLIENT_CID: &[u8] = &[0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
Self::new_initial(
Version::default(),
QuicVersion::default(),
CryptoDxDirection::Write,
"server in",
CLIENT_CID,
@ -729,14 +698,9 @@ pub(crate) struct CryptoDxAppData {
}
impl CryptoDxAppData {
pub fn new(
version: Version,
dir: CryptoDxDirection,
secret: SymKey,
cipher: Cipher,
) -> Res<Self> {
pub fn new(dir: CryptoDxDirection, secret: SymKey, cipher: Cipher) -> Res<Self> {
Ok(Self {
dx: CryptoDxState::new(version, dir, TLS_EPOCH_APPLICATION_DATA, &secret, cipher),
dx: CryptoDxState::new(dir, TLS_EPOCH_APPLICATION_DATA, &secret, cipher),
cipher,
next_secret: Self::update_secret(cipher, &secret)?,
})
@ -773,14 +737,9 @@ pub enum CryptoSpace {
ApplicationData,
}
/// All of the keying material needed for a connection.
///
/// Note that the methods on this struct take a version but those are only ever
/// used for Initial keys; a version has been selected at the time we need to
/// get other keys, so those have fixed versions.
#[derive(Debug, Default)]
pub struct CryptoStates {
initials: HashMap<Version, CryptoState>,
initial: Option<CryptoState>,
handshake: Option<CryptoState>,
zero_rtt: Option<CryptoDxState>, // One direction only!
cipher: Cipher,
@ -798,15 +757,14 @@ impl CryptoStates {
/// not yet available.
pub fn select_tx_mut(
&mut self,
version: Version,
space: PacketNumberSpace,
) -> Option<(CryptoSpace, &mut CryptoDxState)> {
match space {
PacketNumberSpace::Initial => self
.tx_mut(version, CryptoSpace::Initial)
.tx_mut(CryptoSpace::Initial)
.map(|dx| (CryptoSpace::Initial, dx)),
PacketNumberSpace::Handshake => self
.tx_mut(version, CryptoSpace::Handshake)
.tx_mut(CryptoSpace::Handshake)
.map(|dx| (CryptoSpace::Handshake, dx)),
PacketNumberSpace::ApplicationData => {
if let Some(app) = self.app_write.as_mut() {
@ -818,14 +776,10 @@ impl CryptoStates {
}
}
pub fn tx_mut<'a>(
&'a mut self,
version: Version,
cspace: CryptoSpace,
) -> Option<&'a mut CryptoDxState> {
pub fn tx_mut<'a>(&'a mut self, cspace: CryptoSpace) -> Option<&'a mut CryptoDxState> {
let tx = |k: Option<&'a mut CryptoState>| k.map(|dx| &mut dx.tx);
match cspace {
CryptoSpace::Initial => tx(self.initials.get_mut(&version)),
CryptoSpace::Initial => tx(self.initial.as_mut()),
CryptoSpace::ZeroRtt => self
.zero_rtt
.as_mut()
@ -835,10 +789,10 @@ impl CryptoStates {
}
}
pub fn tx<'a>(&'a self, version: Version, cspace: CryptoSpace) -> Option<&'a CryptoDxState> {
pub fn tx<'a>(&'a self, cspace: CryptoSpace) -> Option<&'a CryptoDxState> {
let tx = |k: Option<&'a CryptoState>| k.map(|dx| &dx.tx);
match cspace {
CryptoSpace::Initial => tx(self.initials.get(&version)),
CryptoSpace::Initial => tx(self.initial.as_ref()),
CryptoSpace::ZeroRtt => self
.zero_rtt
.as_ref()
@ -848,17 +802,13 @@ impl CryptoStates {
}
}
pub fn select_tx(
&self,
version: Version,
space: PacketNumberSpace,
) -> Option<(CryptoSpace, &CryptoDxState)> {
pub fn select_tx(&self, space: PacketNumberSpace) -> Option<(CryptoSpace, &CryptoDxState)> {
match space {
PacketNumberSpace::Initial => self
.tx(version, CryptoSpace::Initial)
.tx(CryptoSpace::Initial)
.map(|dx| (CryptoSpace::Initial, dx)),
PacketNumberSpace::Handshake => self
.tx(version, CryptoSpace::Handshake)
.tx(CryptoSpace::Handshake)
.map(|dx| (CryptoSpace::Handshake, dx)),
PacketNumberSpace::ApplicationData => {
if let Some(app) = self.app_write.as_ref() {
@ -870,23 +820,22 @@ impl CryptoStates {
}
}
pub fn rx_hp(&mut self, version: Version, cspace: CryptoSpace) -> Option<&mut CryptoDxState> {
pub fn rx_hp(&mut self, cspace: CryptoSpace) -> Option<&mut CryptoDxState> {
if let CryptoSpace::ApplicationData = cspace {
self.app_read.as_mut().map(|ar| &mut ar.dx)
} else {
self.rx(version, cspace, false)
self.rx(cspace, false)
}
}
pub fn rx<'a>(
&'a mut self,
version: Version,
cspace: CryptoSpace,
key_phase: bool,
) -> Option<&'a mut CryptoDxState> {
let rx = |x: Option<&'a mut CryptoState>| x.map(|dx| &mut dx.rx);
match cspace {
CryptoSpace::Initial => rx(self.initials.get_mut(&version)),
CryptoSpace::Initial => rx(self.initial.as_mut()),
CryptoSpace::ZeroRtt => self
.zero_rtt
.as_mut()
@ -915,101 +864,52 @@ impl CryptoStates {
pub fn rx_pending(&self, space: CryptoSpace) -> bool {
match space {
CryptoSpace::Initial | CryptoSpace::ZeroRtt => false,
CryptoSpace::Handshake => self.handshake.is_none() && !self.initials.is_empty(),
CryptoSpace::Handshake => self.handshake.is_none() && self.initial.is_some(),
CryptoSpace::ApplicationData => self.app_read.is_none(),
}
}
/// Create the initial crypto state.
/// Note that the version here can change and that's OK.
pub fn init<'v, V>(&mut self, versions: V, role: Role, dcid: &[u8])
where
V: IntoIterator<Item = &'v Version>,
{
pub fn init(&mut self, quic_version: QuicVersion, role: Role, dcid: &[u8]) {
const CLIENT_INITIAL_LABEL: &str = "client in";
const SERVER_INITIAL_LABEL: &str = "server in";
qinfo!(
[self],
"Creating initial cipher state role={:?} dcid={}",
role,
hex(dcid)
);
let (write, read) = match role {
Role::Client => (CLIENT_INITIAL_LABEL, SERVER_INITIAL_LABEL),
Role::Server => (SERVER_INITIAL_LABEL, CLIENT_INITIAL_LABEL),
};
for v in versions {
let mut initial = CryptoState {
tx: CryptoDxState::new_initial(quic_version, CryptoDxDirection::Write, write, dcid),
rx: CryptoDxState::new_initial(quic_version, CryptoDxDirection::Read, read, dcid),
};
if let Some(prev) = &self.initial {
qinfo!(
[self],
"Creating initial cipher state v={:?}, role={:?} dcid={}",
v,
role,
hex(dcid)
"Continue packet numbers for initial after retry (write is {:?})",
prev.rx.used_pn,
);
let mut initial = CryptoState {
tx: CryptoDxState::new_initial(*v, CryptoDxDirection::Write, write, dcid),
rx: CryptoDxState::new_initial(*v, CryptoDxDirection::Read, read, dcid),
};
if let Some(prev) = self.initials.get(v) {
qinfo!(
[self],
"Continue packet numbers for initial after retry (write is {:?})",
prev.rx.used_pn,
);
initial.tx.continuation(&prev.tx).unwrap();
}
self.initials.insert(*v, initial);
initial.tx.continuation(&prev.tx).unwrap();
}
self.initial = Some(initial);
}
/// At a server, we can be more targeted in initializing.
/// Initialize on demand: either to decrypt Initial packets that we receive
/// or after a version has been selected.
/// This is maybe slightly inefficient in the first case, because we might
/// not need the send keys if the packet is subsequently discarded, but
/// the overall effort is small enough to write off.
pub fn init_server(&mut self, version: Version, dcid: &[u8]) {
if !self.initials.contains_key(&version) {
self.init(&[version], Role::Server, dcid);
}
}
pub fn confirm_version(&mut self, orig: Version, confirmed: Version) {
if orig != confirmed {
// This part where the old data is removed and then re-added is to
// appease the borrow checker.
// Note that on the server, we might not have initials for |orig| if it
// was configured for |orig| and only |confirmed| Initial packets arrived.
if let Some(prev) = self.initials.remove(&orig) {
let next = self.initials.get_mut(&confirmed).unwrap();
next.tx.continuation(&prev.tx).unwrap();
self.initials.insert(orig, prev);
}
}
}
pub fn set_0rtt_keys(
&mut self,
version: Version,
dir: CryptoDxDirection,
secret: &SymKey,
cipher: Cipher,
) {
pub fn set_0rtt_keys(&mut self, dir: CryptoDxDirection, secret: &SymKey, cipher: Cipher) {
qtrace!([self], "install 0-RTT keys");
self.zero_rtt = Some(CryptoDxState::new(
version,
dir,
TLS_EPOCH_ZERO_RTT,
secret,
cipher,
));
self.zero_rtt = Some(CryptoDxState::new(dir, TLS_EPOCH_ZERO_RTT, secret, cipher));
}
/// Discard keys and return true if that happened.
pub fn discard(&mut self, space: PacketNumberSpace) -> bool {
match space {
PacketNumberSpace::Initial => {
let empty = self.initials.is_empty();
self.initials.clear();
!empty
}
PacketNumberSpace::Initial => self.initial.take().is_some(),
PacketNumberSpace::Handshake => self.handshake.take().is_some(),
PacketNumberSpace::ApplicationData => panic!("Can't drop application data keys"),
}
@ -1026,7 +926,6 @@ impl CryptoStates {
pub fn set_handshake_keys(
&mut self,
version: Version,
write_secret: &SymKey,
read_secret: &SymKey,
cipher: Cipher,
@ -1034,14 +933,12 @@ impl CryptoStates {
self.cipher = cipher;
self.handshake = Some(CryptoState {
tx: CryptoDxState::new(
version,
CryptoDxDirection::Write,
TLS_EPOCH_HANDSHAKE,
write_secret,
cipher,
),
rx: CryptoDxState::new(
version,
CryptoDxDirection::Read,
TLS_EPOCH_HANDSHAKE,
read_secret,
@ -1050,10 +947,10 @@ impl CryptoStates {
});
}
pub fn set_application_write_key(&mut self, version: Version, secret: SymKey) -> Res<()> {
pub fn set_application_write_key(&mut self, secret: SymKey) -> Res<()> {
debug_assert!(self.app_write.is_none());
debug_assert_ne!(self.cipher, 0);
let mut app = CryptoDxAppData::new(version, CryptoDxDirection::Write, secret, self.cipher)?;
let mut app = CryptoDxAppData::new(CryptoDxDirection::Write, secret, self.cipher)?;
if let Some(z) = &self.zero_rtt {
if z.direction == CryptoDxDirection::Write {
app.dx.continuation(z)?;
@ -1064,15 +961,10 @@ impl CryptoStates {
Ok(())
}
pub fn set_application_read_key(
&mut self,
version: Version,
secret: SymKey,
expire_0rtt: Instant,
) -> Res<()> {
pub fn set_application_read_key(&mut self, secret: SymKey, expire_0rtt: Instant) -> Res<()> {
debug_assert!(self.app_write.is_some(), "should have write keys installed");
debug_assert!(self.app_read.is_none());
let mut app = CryptoDxAppData::new(version, CryptoDxDirection::Read, secret, self.cipher)?;
let mut app = CryptoDxAppData::new(CryptoDxDirection::Read, secret, self.cipher)?;
if let Some(z) = &self.zero_rtt {
if z.direction == CryptoDxDirection::Read {
app.dx.continuation(z)?;
@ -1228,16 +1120,11 @@ impl CryptoStates {
cipher: TLS_AES_128_GCM_SHA256,
next_secret: hkdf::import_key(TLS_VERSION_1_3, &[0xaa; 32]).unwrap(),
};
let mut initials = HashMap::new();
initials.insert(
Version::Version1,
CryptoState {
Self {
initial: Some(CryptoState {
tx: CryptoDxState::test_default(),
rx: read(0),
},
);
Self {
initials,
}),
handshake: None,
zero_rtt: None,
cipher: TLS_AES_128_GCM_SHA256,
@ -1259,14 +1146,13 @@ impl CryptoStates {
let secret = hkdf::import_key(TLS_VERSION_1_3, SECRET).unwrap();
let app_read = |epoch| CryptoDxAppData {
dx: CryptoDxState {
version: Version::Version1,
direction: CryptoDxDirection::Read,
epoch,
aead: Aead::new(
TLS_VERSION_1_3,
TLS_CHACHA20_POLY1305_SHA256,
&secret,
"quic ", // This is a v1 test so hard-code the label.
"quic ",
)
.unwrap(),
hpkey: HpKey::extract(
@ -1284,7 +1170,7 @@ impl CryptoStates {
next_secret: secret.clone(),
};
Self {
initials: HashMap::new(),
initial: None,
handshake: None,
zero_rtt: None,
cipher: TLS_CHACHA20_POLY1305_SHA256,

View File

@ -36,7 +36,6 @@ pub mod stream_id;
pub mod streams;
pub mod tparams;
mod tracking;
pub mod version;
pub use self::cc::CongestionControlAlgorithm;
pub use self::cid::{
@ -48,9 +47,9 @@ pub use self::connection::{
};
pub use self::events::{ConnectionEvent, ConnectionEvents};
pub use self::frame::CloseError;
pub use self::packet::QuicVersion;
pub use self::stats::Stats;
pub use self::stream_id::{StreamId, StreamType};
pub use self::version::Version;
pub use self::recv_stream::RECV_BUFFER_SIZE;
pub use self::send_stream::SEND_BUFFER_SIZE;
@ -87,7 +86,6 @@ pub enum Error {
ConnectionState,
DecodingFrame,
DecryptError,
DisabledVersion,
HandshakeFailed,
IdleTimeout,
IntegerOverflow,
@ -97,7 +95,7 @@ pub enum Error {
InvalidResumptionToken,
InvalidRetry,
InvalidStreamId,
KeysDiscarded(crypto::CryptoSpace),
KeysDiscarded,
/// Packet protection keys are exhausted.
/// Also used when too many key updates have happened.
KeysExhausted,
@ -145,7 +143,6 @@ impl Error {
// As we have a special error code for ECH fallbacks, we lose the alert.
// Send the server "ech_required" directly.
Self::EchRetry(_) => 0x100 + 121,
Self::VersionNegotiation => 0x53f8,
// All the rest are internal errors.
_ => 1,
}

View File

@ -7,7 +7,6 @@
// Encoding and decoding packets off the wire.
use crate::cid::{ConnectionId, ConnectionIdDecoder, ConnectionIdRef, MAX_CONNECTION_ID_LEN};
use crate::crypto::{CryptoDxState, CryptoSpace, CryptoStates};
use crate::version::{Version, WireVersion};
use crate::{Error, Res};
use neqo_common::{hex, hex_with_len, qtrace, qwarn, Decoder, Encoder};
@ -20,6 +19,11 @@ use std::iter::ExactSizeIterator;
use std::ops::{Deref, DerefMut, Range};
use std::time::Instant;
const PACKET_TYPE_INITIAL: u8 = 0x0;
const PACKET_TYPE_0RTT: u8 = 0x01;
const PACKET_TYPE_HANDSHAKE: u8 = 0x2;
const PACKET_TYPE_RETRY: u8 = 0x03;
pub const PACKET_BIT_LONG: u8 = 0x80;
const PACKET_BIT_SHORT: u8 = 0x00;
const PACKET_BIT_FIXED_QUIC: u8 = 0x40;
@ -36,6 +40,7 @@ const MAX_PACKET_NUMBER_LEN: usize = 4;
mod retry;
pub type PacketNumber = u64;
type Version = u32;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PacketType {
@ -50,29 +55,15 @@ pub enum PacketType {
impl PacketType {
#[must_use]
fn from_byte(t: u8, v: Version) -> Self {
// Version2 adds one to the type, modulo 4
match t.wrapping_sub(u8::from(v == Version::Version2)) & 3 {
0 => Self::Initial,
1 => Self::ZeroRtt,
2 => Self::Handshake,
3 => Self::Retry,
_ => panic!("packet type out of range"),
fn code(self) -> u8 {
match self {
Self::Initial => PACKET_TYPE_INITIAL,
Self::ZeroRtt => PACKET_TYPE_0RTT,
Self::Handshake => PACKET_TYPE_HANDSHAKE,
Self::Retry => PACKET_TYPE_RETRY,
_ => panic!("shouldn't be here"),
}
}
#[must_use]
fn to_byte(self, v: Version) -> u8 {
let t = match self {
Self::Initial => 0,
Self::ZeroRtt => 1,
Self::Handshake => 2,
Self::Retry => 3,
_ => panic!("not a long header packet type"),
};
// Version2 adds one to the type, modulo 4
(t + u8::from(v == Version::Version2)) & 3
}
}
impl From<PacketType> for CryptoSpace {
@ -98,6 +89,53 @@ impl From<CryptoSpace> for PacketType {
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum QuicVersion {
Version1,
Draft29,
Draft30,
Draft31,
Draft32,
}
impl QuicVersion {
pub fn as_u32(self) -> Version {
match self {
Self::Version1 => 1,
Self::Draft29 => 0xff00_0000 + 29,
Self::Draft30 => 0xff00_0000 + 30,
Self::Draft31 => 0xff00_0000 + 31,
Self::Draft32 => 0xff00_0000 + 32,
}
}
}
impl Default for QuicVersion {
fn default() -> Self {
Self::Version1
}
}
impl TryFrom<Version> for QuicVersion {
type Error = Error;
fn try_from(ver: Version) -> Res<Self> {
if ver == 1 {
Ok(Self::Version1)
} else if ver == 0xff00_0000 + 29 {
Ok(Self::Draft29)
} else if ver == 0xff00_0000 + 30 {
Ok(Self::Draft30)
} else if ver == 0xff00_0000 + 31 {
Ok(Self::Draft31)
} else if ver == 0xff00_0000 + 32 {
Ok(Self::Draft32)
} else {
Err(Error::VersionNegotiation)
}
}
}
struct PacketBuilderOffsets {
/// The bits of the first octet that need masking.
first_byte_mask: u8,
@ -176,7 +214,7 @@ impl PacketBuilder {
pub fn long(
mut encoder: Encoder,
pt: PacketType,
version: Version,
quic_version: QuicVersion,
dcid: impl AsRef<[u8]>,
scid: impl AsRef<[u8]>,
) -> Self {
@ -187,8 +225,8 @@ impl PacketBuilder {
if limit > encoder.len()
&& 11 + dcid.as_ref().len() + scid.as_ref().len() < limit - encoder.len()
{
encoder.encode_byte(PACKET_BIT_LONG | PACKET_BIT_FIXED_QUIC | pt.to_byte(version) << 4);
encoder.encode_uint(4, version.wire_version());
encoder.encode_byte(PACKET_BIT_LONG | PACKET_BIT_FIXED_QUIC | pt.code() << 4);
encoder.encode_uint(4, quic_version.as_u32());
encoder.encode_vec(1, dcid.as_ref());
encoder.encode_vec(1, scid.as_ref());
} else {
@ -210,7 +248,7 @@ impl PacketBuilder {
}
fn is_long(&self) -> bool {
self.as_ref()[self.header.start] & 0x80 == PACKET_BIT_LONG
self[self.header.start] & 0x80 == PACKET_BIT_LONG
}
/// This stores a value that can be used as a limit. This does not cause
@ -267,12 +305,16 @@ impl PacketBuilder {
let mask = if quic_bit { PACKET_BIT_FIXED_QUIC } else { 0 }
| if self.is_long() { 0 } else { PACKET_BIT_SPIN };
let first = self.header.start;
self.encoder.as_mut()[first] ^= random(1)[0] & mask;
self[first] ^= random(1)[0] & mask;
}
/// For an Initial packet, encode the token.
/// If you fail to do this, then you will not get a valid packet.
pub fn initial_token(&mut self, token: &[u8]) {
debug_assert_eq!(
self.encoder[self.header.start] & 0xb0,
PACKET_BIT_LONG | PACKET_TYPE_INITIAL << 4
);
if Encoder::vvec_len(token.len()) < self.remaining() {
self.encoder.encode_vvec(token);
} else {
@ -306,15 +348,15 @@ impl PacketBuilder {
self.offsets.pn = pn_offset..self.encoder.len();
// Now encode the packet number length and save the header length.
self.encoder.as_mut()[self.header.start] |= u8::try_from(pn_len - 1).unwrap();
self.encoder[self.header.start] |= u8::try_from(pn_len - 1).unwrap();
self.header.end = self.encoder.len();
self.pn = pn;
}
fn write_len(&mut self, expansion: usize) {
let len = self.encoder.len() - (self.offsets.len + 2) + expansion;
self.encoder.as_mut()[self.offsets.len] = 0x40 | ((len >> 8) & 0x3f) as u8;
self.encoder.as_mut()[self.offsets.len + 1] = (len & 0xff) as u8;
self.encoder[self.offsets.len] = 0x40 | ((len >> 8) & 0x3f) as u8;
self.encoder[self.offsets.len + 1] = (len & 0xff) as u8;
}
fn pad_for_crypto(&mut self, crypto: &mut CryptoDxState) {
@ -360,8 +402,8 @@ impl PacketBuilder {
self.write_len(crypto.expansion());
}
let hdr = &self.encoder.as_ref()[self.header.clone()];
let body = &self.encoder.as_ref()[self.header.end..];
let hdr = &self.encoder[self.header.clone()];
let body = &self.encoder[self.header.end..];
qtrace!(
"Packet build pn={} hdr={} body={}",
self.pn,
@ -377,9 +419,9 @@ impl PacketBuilder {
let mask = crypto.compute_mask(sample)?;
// Apply the mask.
self.encoder.as_mut()[self.header.start] ^= mask[0] & self.offsets.first_byte_mask;
self.encoder[self.header.start] ^= mask[0] & self.offsets.first_byte_mask;
for (i, j) in (1..=self.offsets.pn.len()).zip(self.offsets.pn) {
self.encoder.as_mut()[j] ^= mask[i];
self.encoder[j] ^= mask[i];
}
// Finally, cut off the plaintext and add back the ciphertext.
@ -407,7 +449,7 @@ impl PacketBuilder {
/// As Retry is odd (it has to be constructed with leading bytes),
/// this returns a Vec<u8> rather than building on an encoder.
pub fn retry(
version: Version,
quic_version: QuicVersion,
dcid: &[u8],
scid: &[u8],
token: &[u8],
@ -419,17 +461,17 @@ impl PacketBuilder {
encoder.encode_byte(
PACKET_BIT_LONG
| PACKET_BIT_FIXED_QUIC
| (PacketType::Retry.to_byte(version) << 4)
| (PACKET_TYPE_RETRY << 4)
| (random(1)[0] & 0xf),
);
encoder.encode_uint(4, version.wire_version());
encoder.encode_uint(4, quic_version.as_u32());
encoder.encode_vec(1, dcid);
encoder.encode_vec(1, scid);
debug_assert_ne!(token.len(), 0);
encoder.encode(token);
let tag = retry::use_aead(version, |aead| {
let tag = retry::use_aead(quic_version, |aead| {
let mut buf = vec![0; aead.expansion()];
Ok(aead.encrypt(0, encoder.as_ref(), &[], &mut buf)?.to_vec())
Ok(aead.encrypt(0, &encoder, &[], &mut buf)?.to_vec())
})?;
encoder.encode(&tag);
let mut complete: Vec<u8> = encoder.into();
@ -437,34 +479,25 @@ impl PacketBuilder {
}
/// Make a Version Negotiation packet.
pub fn version_negotiation(
dcid: &[u8],
scid: &[u8],
client_version: u32,
versions: &[Version],
) -> Vec<u8> {
pub fn version_negotiation(dcid: &[u8], scid: &[u8]) -> Vec<u8> {
let mut encoder = Encoder::default();
let mut grease = random(4);
let mut grease = random(5);
// This will not include the "QUIC bit" sometimes. Intentionally.
encoder.encode_byte(PACKET_BIT_LONG | (grease[3] & 0x7f));
encoder.encode_byte(PACKET_BIT_LONG | (grease[4] & 0x7f));
encoder.encode(&[0; 4]); // Zero version == VN.
encoder.encode_vec(1, dcid);
encoder.encode_vec(1, scid);
for v in versions {
encoder.encode_uint(4, v.wire_version());
}
encoder.encode_uint(4, QuicVersion::Version1.as_u32());
encoder.encode_uint(4, QuicVersion::Draft29.as_u32());
encoder.encode_uint(4, QuicVersion::Draft30.as_u32());
encoder.encode_uint(4, QuicVersion::Draft31.as_u32());
encoder.encode_uint(4, QuicVersion::Draft32.as_u32());
// Add a greased version, using the randomness already generated.
for g in &mut grease[..3] {
for g in &mut grease[..4] {
*g = *g & 0xf0 | 0x0a;
}
// Ensure our greased version does not collide with the client version
// by making the last byte differ from the client initial.
grease[3] = (client_version.wrapping_add(0x10) & 0xf0) as u8 | 0x0a;
encoder.encode(&grease[..4]);
Vec::from(encoder)
encoder.encode(&grease[0..4]);
encoder.into()
}
}
@ -503,7 +536,7 @@ pub struct PublicPacket<'a> {
/// The size of the header, not including the packet number.
header_len: usize,
/// Protocol version, if present in header.
version: Option<WireVersion>,
quic_version: Option<QuicVersion>,
/// A reference to the entire packet, including the header.
data: &'a [u8],
}
@ -523,11 +556,11 @@ impl<'a> PublicPacket<'a> {
fn decode_long(
decoder: &mut Decoder<'a>,
packet_type: PacketType,
version: Version,
quic_version: QuicVersion,
) -> Res<(&'a [u8], usize)> {
if packet_type == PacketType::Retry {
let header_len = decoder.offset();
let expansion = retry::expansion(version);
let expansion = retry::expansion(quic_version);
let token = Self::opt(decoder.decode(decoder.remaining() - expansion))?;
if token.is_empty() {
return Err(Error::InvalidPacket);
@ -570,7 +603,7 @@ impl<'a> PublicPacket<'a> {
scid: None,
token: &[],
header_len,
version: None,
quic_version: None,
data,
},
&[],
@ -578,7 +611,7 @@ impl<'a> PublicPacket<'a> {
}
// Generic long header.
let version = WireVersion::try_from(Self::opt(decoder.decode_uint(4))?).unwrap();
let version = Version::try_from(Self::opt(decoder.decode_uint(4))?).unwrap();
let dcid = ConnectionIdRef::from(Self::opt(decoder.decode_vec(1))?);
let scid = ConnectionIdRef::from(Self::opt(decoder.decode_vec(1))?);
@ -591,7 +624,7 @@ impl<'a> PublicPacket<'a> {
scid: Some(scid),
token: &[],
header_len: decoder.offset(),
version: None,
quic_version: None,
data,
},
&[],
@ -599,7 +632,7 @@ impl<'a> PublicPacket<'a> {
}
// Check that this is a long header from a supported version.
let version = if let Ok(v) = Version::try_from(version) {
let quic_version = if let Ok(v) = QuicVersion::try_from(version) {
v
} else {
return Ok((
@ -609,7 +642,7 @@ impl<'a> PublicPacket<'a> {
scid: Some(scid),
token: &[],
header_len: decoder.offset(),
version: Some(version),
quic_version: None,
data,
},
&[],
@ -619,10 +652,16 @@ impl<'a> PublicPacket<'a> {
if dcid.len() > MAX_CONNECTION_ID_LEN || scid.len() > MAX_CONNECTION_ID_LEN {
return Err(Error::InvalidPacket);
}
let packet_type = PacketType::from_byte((first >> 4) & 3, version);
let packet_type = match (first >> 4) & 3 {
PACKET_TYPE_INITIAL => PacketType::Initial,
PACKET_TYPE_0RTT => PacketType::ZeroRtt,
PACKET_TYPE_HANDSHAKE => PacketType::Handshake,
PACKET_TYPE_RETRY => PacketType::Retry,
_ => unreachable!(),
};
// The type-specific code includes a token. This consumes the remainder of the packet.
let (token, header_len) = Self::decode_long(&mut decoder, packet_type, version)?;
let (token, header_len) = Self::decode_long(&mut decoder, packet_type, quic_version)?;
let end = data.len() - decoder.remaining();
let (data, remainder) = data.split_at(end);
Ok((
@ -632,7 +671,7 @@ impl<'a> PublicPacket<'a> {
scid: Some(scid),
token,
header_len,
version: Some(version.wire_version()),
quic_version: Some(quic_version),
data,
},
remainder,
@ -644,7 +683,7 @@ impl<'a> PublicPacket<'a> {
if self.packet_type != PacketType::Retry {
return false;
}
let version = self.version().unwrap();
let version = self.quic_version.unwrap();
let expansion = retry::expansion(version);
if self.data.len() <= expansion {
return false;
@ -655,7 +694,7 @@ impl<'a> PublicPacket<'a> {
encoder.encode(header);
retry::use_aead(version, |aead| {
let mut buf = vec![0; expansion];
Ok(aead.decrypt(0, encoder.as_ref(), tag, &mut buf)?.is_empty())
Ok(aead.decrypt(0, &encoder, tag, &mut buf)?.is_empty())
})
.unwrap_or(false)
}
@ -685,13 +724,8 @@ impl<'a> PublicPacket<'a> {
self.token
}
pub fn version(&self) -> Option<Version> {
self.version.and_then(|v| Version::try_from(v).ok())
}
pub fn wire_version(&self) -> WireVersion {
debug_assert!(self.version.is_some());
self.version.unwrap_or(0)
pub fn version(&self) -> Option<QuicVersion> {
self.quic_version
}
pub fn len(&self) -> usize {
@ -774,20 +808,16 @@ impl<'a> PublicPacket<'a> {
pub fn decrypt(&self, crypto: &mut CryptoStates, release_at: Instant) -> Res<DecryptedPacket> {
let cspace: CryptoSpace = self.packet_type.into();
// When we don't have a version, the crypto code doesn't need a version
// for lookup, so use the default, but fix it up if decryption succeeds.
let version = self.version().unwrap_or_default();
// This has to work in two stages because we need to remove header protection
// before picking the keys to use.
if let Some(rx) = crypto.rx_hp(version, cspace) {
if let Some(rx) = crypto.rx_hp(cspace) {
// Note that this will dump early, which creates a side-channel.
// This is OK in this case because we the only reason this can
// fail is if the cryptographic module is bad or the packet is
// too small (which is public information).
let (key_phase, pn, header, body) = self.decrypt_header(rx)?;
qtrace!([rx], "decoded header: {:?}", header);
let rx = crypto.rx(version, cspace, key_phase).unwrap();
let version = rx.version(); // Version fixup; see above.
let rx = crypto.rx(cspace, key_phase).unwrap();
let d = rx.decrypt(pn, &header, body)?;
// If this is the first packet ever successfully decrypted
// using `rx`, make sure to initiate a key update.
@ -796,7 +826,6 @@ impl<'a> PublicPacket<'a> {
}
crypto.check_pn_overlap()?;
Ok(DecryptedPacket {
version,
pt: self.packet_type,
pn,
data: d,
@ -805,16 +834,16 @@ impl<'a> PublicPacket<'a> {
Err(Error::KeysPending(cspace))
} else {
qtrace!("keys for {:?} already discarded", cspace);
Err(Error::KeysDiscarded(cspace))
Err(Error::KeysDiscarded)
}
}
pub fn supported_versions(&self) -> Res<Vec<WireVersion>> {
pub fn supported_versions(&self) -> Res<Vec<Version>> {
assert_eq!(self.packet_type, PacketType::VersionNegotiation);
let mut decoder = Decoder::new(&self.data[self.header_len..]);
let mut res = Vec::new();
while decoder.remaining() > 0 {
let version = WireVersion::try_from(Self::opt(decoder.decode_uint(4))?)?;
let version = Version::try_from(Self::opt(decoder.decode_uint(4))?)?;
res.push(version);
}
Ok(res)
@ -834,17 +863,12 @@ impl fmt::Debug for PublicPacket<'_> {
}
pub struct DecryptedPacket {
version: Version,
pt: PacketType,
pn: PacketNumber,
data: Vec<u8>,
}
impl DecryptedPacket {
pub fn version(&self) -> Version {
self.version
}
pub fn packet_type(&self) -> PacketType {
self.pt
}
@ -866,7 +890,7 @@ impl Deref for DecryptedPacket {
mod tests {
use super::*;
use crate::crypto::{CryptoDxState, CryptoStates};
use crate::{EmptyConnectionIdGenerator, RandomConnectionIdGenerator, Version};
use crate::{EmptyConnectionIdGenerator, QuicVersion, RandomConnectionIdGenerator};
use neqo_common::Encoder;
use test_fixture::{fixture_init, now};
@ -912,7 +936,7 @@ mod tests {
let mut builder = PacketBuilder::long(
Encoder::new(),
PacketType::Initial,
Version::default(),
QuicVersion::default(),
&ConnectionId::from(&[][..]),
&ConnectionId::from(SERVER_CID),
);
@ -920,7 +944,7 @@ mod tests {
builder.pn(1, 2);
builder.encode(SAMPLE_INITIAL_PAYLOAD);
let packet = builder.build(&mut prot).expect("build");
assert_eq!(packet.as_ref(), SAMPLE_INITIAL);
assert_eq!(&packet[..], SAMPLE_INITIAL);
}
#[test]
@ -947,24 +971,24 @@ mod tests {
fn disallow_long_dcid() {
let mut enc = Encoder::new();
enc.encode_byte(PACKET_BIT_LONG | PACKET_BIT_FIXED_QUIC);
enc.encode_uint(4, Version::default().wire_version());
enc.encode_uint(4, QuicVersion::default().as_u32());
enc.encode_vec(1, &[0x00; MAX_CONNECTION_ID_LEN + 1]);
enc.encode_vec(1, &[]);
enc.encode(&[0xff; 40]); // junk
assert!(PublicPacket::decode(enc.as_ref(), &cid_mgr()).is_err());
assert!(PublicPacket::decode(&enc, &cid_mgr()).is_err());
}
#[test]
fn disallow_long_scid() {
let mut enc = Encoder::new();
enc.encode_byte(PACKET_BIT_LONG | PACKET_BIT_FIXED_QUIC);
enc.encode_uint(4, Version::default().wire_version());
enc.encode_uint(4, QuicVersion::default().as_u32());
enc.encode_vec(1, &[]);
enc.encode_vec(1, &[0x00; MAX_CONNECTION_ID_LEN + 2]);
enc.encode(&[0xff; 40]); // junk
assert!(PublicPacket::decode(enc.as_ref(), &cid_mgr()).is_err());
assert!(PublicPacket::decode(&enc, &cid_mgr()).is_err());
}
const SAMPLE_SHORT: &[u8] = &[
@ -983,7 +1007,7 @@ mod tests {
let packet = builder
.build(&mut CryptoDxState::test_default())
.expect("build");
assert_eq!(packet.as_ref(), SAMPLE_SHORT);
assert_eq!(&packet[..], SAMPLE_SHORT);
}
#[test]
@ -995,7 +1019,7 @@ mod tests {
PacketBuilder::short(Encoder::new(), true, &ConnectionId::from(SERVER_CID));
builder.scramble(true);
builder.pn(0, 1);
firsts.push(builder.as_ref()[0]);
firsts.push(builder[0]);
}
let is_set = |bit| move |v| v & bit == bit;
// There should be at least one value with the QUIC bit set:
@ -1053,7 +1077,7 @@ mod tests {
let mut builder = PacketBuilder::long(
Encoder::new(),
PacketType::Handshake,
Version::default(),
QuicVersion::default(),
&ConnectionId::from(SERVER_CID),
&ConnectionId::from(CLIENT_CID),
);
@ -1068,8 +1092,8 @@ mod tests {
builder.encode(&[0]); // Minimal size (packet number is big enough).
let encoder = builder.build(&mut prot).expect("build");
assert_eq!(
first.as_ref(),
&encoder.as_ref()[..first.len()],
&first[..],
&encoder[..first.len()],
"the first packet should be a prefix"
);
assert_eq!(encoder.len(), 45 + 29);
@ -1087,14 +1111,14 @@ mod tests {
let mut builder = PacketBuilder::long(
Encoder::new(),
PacketType::Handshake,
Version::default(),
QuicVersion::default(),
&ConnectionId::from(&[][..]),
&ConnectionId::from(&[][..]),
);
builder.pn(0, 1);
builder.encode(&[1, 2, 3]);
let packet = builder.build(&mut CryptoDxState::test_default()).unwrap();
assert_eq!(packet.as_ref(), EXPECTED);
assert_eq!(&packet[..], EXPECTED);
}
#[test]
@ -1106,13 +1130,13 @@ mod tests {
let mut builder = PacketBuilder::long(
Encoder::new(),
PacketType::Handshake,
Version::default(),
QuicVersion::default(),
&ConnectionId::from(&[][..]),
&ConnectionId::from(&[][..]),
);
builder.pn(0, 1);
builder.scramble(true);
if (builder.as_ref()[0] & PACKET_BIT_FIXED_QUIC) == 0 {
if (builder[0] & PACKET_BIT_FIXED_QUIC) == 0 {
found_unset = true;
} else {
found_set = true;
@ -1127,7 +1151,7 @@ mod tests {
let mut builder = PacketBuilder::long(
Encoder::new(),
PacketType::Initial,
Version::default(),
QuicVersion::default(),
&ConnectionId::from(&[][..]),
&ConnectionId::from(SERVER_CID),
);
@ -1161,7 +1185,7 @@ mod tests {
let builder = PacketBuilder::long(
encoder,
PacketType::Initial,
Version::default(),
QuicVersion::default(),
&ConnectionId::from(SERVER_CID),
&ConnectionId::from(SERVER_CID),
);
@ -1169,12 +1193,6 @@ mod tests {
assert_eq!(builder.abort(), encoder_copy);
}
const SAMPLE_RETRY_V2: &[u8] = &[
0xcf, 0x70, 0x9a, 0x50, 0xc4, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5,
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x1d, 0xc7, 0x11, 0x30, 0xcd, 0x1e, 0xd3, 0x9d, 0x6e, 0xfc,
0xee, 0x5c, 0x85, 0x80, 0x65, 0x01,
];
const SAMPLE_RETRY_V1: &[u8] = &[
0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5,
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x04, 0xa2, 0x65, 0xba, 0x2e, 0xff, 0x4d, 0x82, 0x90, 0x58,
@ -1207,10 +1225,10 @@ mod tests {
const RETRY_TOKEN: &[u8] = b"token";
fn build_retry_single(version: Version, sample_retry: &[u8]) {
fn build_retry_single(quic_version: QuicVersion, sample_retry: &[u8]) {
fixture_init();
let retry =
PacketBuilder::retry(version, &[], SERVER_CID, RETRY_TOKEN, CLIENT_CID).unwrap();
PacketBuilder::retry(quic_version, &[], SERVER_CID, RETRY_TOKEN, CLIENT_CID).unwrap();
let (packet, remainder) = PublicPacket::decode(&retry, &cid_mgr()).unwrap();
assert!(packet.is_valid_retry(&ConnectionId::from(CLIENT_CID)));
@ -1222,43 +1240,35 @@ mod tests {
assert_eq!(&retry, &sample_retry);
} else {
// Otherwise, just check that the header is OK.
assert_eq!(
retry[0] & 0xf0,
0xc0 | (PacketType::Retry.to_byte(version) << 4)
);
assert_eq!(retry[0] & 0xf0, 0xf0);
let header_range = 1..retry.len() - 16;
assert_eq!(&retry[header_range.clone()], &sample_retry[header_range]);
}
}
#[test]
fn build_retry_v2() {
build_retry_single(Version::Version2, SAMPLE_RETRY_V2);
}
#[test]
fn build_retry_v1() {
build_retry_single(Version::Version1, SAMPLE_RETRY_V1);
build_retry_single(QuicVersion::Version1, SAMPLE_RETRY_V1);
}
#[test]
fn build_retry_29() {
build_retry_single(Version::Draft29, SAMPLE_RETRY_29);
build_retry_single(QuicVersion::Draft29, SAMPLE_RETRY_29);
}
#[test]
fn build_retry_30() {
build_retry_single(Version::Draft30, SAMPLE_RETRY_30);
build_retry_single(QuicVersion::Draft30, SAMPLE_RETRY_30);
}
#[test]
fn build_retry_31() {
build_retry_single(Version::Draft31, SAMPLE_RETRY_31);
build_retry_single(QuicVersion::Draft31, SAMPLE_RETRY_31);
}
#[test]
fn build_retry_32() {
build_retry_single(Version::Draft32, SAMPLE_RETRY_32);
build_retry_single(QuicVersion::Draft32, SAMPLE_RETRY_32);
}
#[test]
@ -1267,7 +1277,6 @@ mod tests {
// Odds are approximately 1 in 8 that the full comparison doesn't happen
// for a given version.
for _ in 0..32 {
build_retry_v2();
build_retry_v1();
build_retry_29();
build_retry_30();
@ -1276,46 +1285,36 @@ mod tests {
}
}
fn decode_retry(version: Version, sample_retry: &[u8]) {
fn decode_retry(quic_version: QuicVersion, sample_retry: &[u8]) {
fixture_init();
let (packet, remainder) =
PublicPacket::decode(sample_retry, &RandomConnectionIdGenerator::new(5)).unwrap();
assert!(packet.is_valid_retry(&ConnectionId::from(CLIENT_CID)));
assert_eq!(Some(version), packet.version());
assert_eq!(Some(quic_version), packet.quic_version);
assert!(packet.dcid().is_empty());
assert_eq!(&packet.scid()[..], SERVER_CID);
assert_eq!(packet.token(), RETRY_TOKEN);
assert!(remainder.is_empty());
}
#[test]
fn decode_retry_v2() {
decode_retry(Version::Version2, SAMPLE_RETRY_V2);
}
#[test]
fn decode_retry_v1() {
decode_retry(Version::Version1, SAMPLE_RETRY_V1);
}
#[test]
fn decode_retry_29() {
decode_retry(Version::Draft29, SAMPLE_RETRY_29);
decode_retry(QuicVersion::Draft29, SAMPLE_RETRY_29);
}
#[test]
fn decode_retry_30() {
decode_retry(Version::Draft30, SAMPLE_RETRY_30);
decode_retry(QuicVersion::Draft30, SAMPLE_RETRY_30);
}
#[test]
fn decode_retry_31() {
decode_retry(Version::Draft31, SAMPLE_RETRY_31);
decode_retry(QuicVersion::Draft31, SAMPLE_RETRY_31);
}
#[test]
fn decode_retry_32() {
decode_retry(Version::Draft32, SAMPLE_RETRY_32);
decode_retry(QuicVersion::Draft32, SAMPLE_RETRY_32);
}
/// Check some packets that are clearly not valid Retry packets.
@ -1327,11 +1326,11 @@ mod tests {
assert!(PublicPacket::decode(&[], &cid_mgr).is_err());
let (packet, remainder) = PublicPacket::decode(SAMPLE_RETRY_V1, &cid_mgr).unwrap();
let (packet, remainder) = PublicPacket::decode(SAMPLE_RETRY_29, &cid_mgr).unwrap();
assert!(remainder.is_empty());
assert!(packet.is_valid_retry(&odcid));
let mut damaged_retry = SAMPLE_RETRY_V1.to_vec();
let mut damaged_retry = SAMPLE_RETRY_29.to_vec();
let last = damaged_retry.len() - 1;
damaged_retry[last] ^= 66;
let (packet, remainder) = PublicPacket::decode(&damaged_retry, &cid_mgr).unwrap();
@ -1353,16 +1352,15 @@ mod tests {
const SAMPLE_VN: &[u8] = &[
0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, 0x08,
0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x70, 0x9a, 0x50, 0xc4, 0x00, 0x00, 0x00,
0x01, 0xff, 0x00, 0x00, 0x20, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x1e, 0xff, 0x00,
0x00, 0x1d, 0x0a, 0x0a, 0x0a, 0x0a,
0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00,
0x1d, 0xff, 0x00, 0x00, 0x1e, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x20, 0x0a, 0x0a,
0x0a, 0x0a,
];
#[test]
fn build_vn() {
fixture_init();
let mut vn =
PacketBuilder::version_negotiation(SERVER_CID, CLIENT_CID, 0x0a0a0a0a, &Version::all());
let mut vn = PacketBuilder::version_negotiation(SERVER_CID, CLIENT_CID);
// Erase randomness from greasing...
assert_eq!(vn.len(), SAMPLE_VN.len());
vn[0] &= 0x80;
@ -1372,14 +1370,6 @@ mod tests {
assert_eq!(&vn, &SAMPLE_VN);
}
#[test]
fn vn_do_not_repeat_client_grease() {
fixture_init();
let vn =
PacketBuilder::version_negotiation(SERVER_CID, CLIENT_CID, 0x0a0a0a0a, &Version::all());
assert_ne!(&vn[SAMPLE_VN.len() - 4..], &[0x0a, 0x0a, 0x0a, 0x0a]);
}
#[test]
fn parse_vn() {
let (packet, remainder) =
@ -1400,11 +1390,11 @@ mod tests {
enc.encode_vec(1, BIG_DCID);
enc.encode_vec(1, BIG_SCID);
enc.encode_uint(4, 0x1a2a_3a4a_u64);
enc.encode_uint(4, Version::default().wire_version());
enc.encode_uint(4, QuicVersion::default().as_u32());
enc.encode_uint(4, 0x5a6a_7a8a_u64);
let (packet, remainder) =
PublicPacket::decode(enc.as_ref(), &EmptyConnectionIdGenerator::default()).unwrap();
PublicPacket::decode(&enc, &EmptyConnectionIdGenerator::default()).unwrap();
assert!(remainder.is_empty());
assert_eq!(&packet.dcid[..], BIG_DCID);
assert!(packet.scid.is_some());

View File

@ -6,7 +6,7 @@
#![deny(clippy::pedantic)]
use crate::version::Version;
use crate::packet::QuicVersion;
use crate::{Error, Res};
use neqo_common::qerror;
@ -14,33 +14,37 @@ use neqo_crypto::{hkdf, Aead, TLS_AES_128_GCM_SHA256, TLS_VERSION_1_3};
use std::cell::RefCell;
const RETRY_SECRET_29: &[u8] = &[
0x8b, 0x0d, 0x37, 0xeb, 0x85, 0x35, 0x02, 0x2e, 0xbc, 0x8d, 0x76, 0xa2, 0x07, 0xd8, 0x0d, 0xf2,
0x26, 0x46, 0xec, 0x06, 0xdc, 0x80, 0x96, 0x42, 0xc3, 0x0a, 0x8b, 0xaa, 0x2b, 0xaa, 0xff, 0x4c,
];
const RETRY_SECRET_V1: &[u8] = &[
0xd9, 0xc9, 0x94, 0x3e, 0x61, 0x01, 0xfd, 0x20, 0x00, 0x21, 0x50, 0x6b, 0xcc, 0x02, 0x81, 0x4c,
0x73, 0x03, 0x0f, 0x25, 0xc7, 0x9d, 0x71, 0xce, 0x87, 0x6e, 0xca, 0x87, 0x6e, 0x6f, 0xca, 0x8e,
];
/// The AEAD used for Retry is fixed, so use thread local storage.
fn make_aead(version: Version) -> Aead {
fn make_aead(secret: &[u8]) -> Aead {
#[cfg(debug_assertions)]
::neqo_crypto::assert_initialized();
let secret = hkdf::import_key(TLS_VERSION_1_3, version.retry_secret()).unwrap();
Aead::new(
TLS_VERSION_1_3,
TLS_AES_128_GCM_SHA256,
&secret,
version.label_prefix(),
)
.unwrap()
let secret = hkdf::import_key(TLS_VERSION_1_3, secret).unwrap();
Aead::new(TLS_VERSION_1_3, TLS_AES_128_GCM_SHA256, &secret, "quic ").unwrap()
}
thread_local!(static RETRY_AEAD_29: RefCell<Aead> = RefCell::new(make_aead(Version::Draft29)));
thread_local!(static RETRY_AEAD_V1: RefCell<Aead> = RefCell::new(make_aead(Version::Version1)));
thread_local!(static RETRY_AEAD_V2: RefCell<Aead> = RefCell::new(make_aead(Version::Version2)));
thread_local!(static RETRY_AEAD_29: RefCell<Aead> = RefCell::new(make_aead(RETRY_SECRET_29)));
thread_local!(static RETRY_AEAD_V1: RefCell<Aead> = RefCell::new(make_aead(RETRY_SECRET_V1)));
/// Run a function with the appropriate Retry AEAD.
pub fn use_aead<F, T>(version: Version, f: F) -> Res<T>
pub fn use_aead<F, T>(quic_version: QuicVersion, f: F) -> Res<T>
where
F: FnOnce(&Aead) -> Res<T>,
{
match version {
Version::Version2 => &RETRY_AEAD_V2,
Version::Version1 => &RETRY_AEAD_V1,
Version::Draft29 | Version::Draft30 | Version::Draft31 | Version::Draft32 => &RETRY_AEAD_29,
match quic_version {
QuicVersion::Version1 => &RETRY_AEAD_V1,
QuicVersion::Draft29
| QuicVersion::Draft30
| QuicVersion::Draft31
| QuicVersion::Draft32 => &RETRY_AEAD_29,
}
.try_with(|aead| f(&aead.borrow()))
.map_err(|e| {
@ -50,8 +54,8 @@ where
}
/// Determine how large the expansion is for a given key.
pub fn expansion(version: Version) -> usize {
if let Ok(ex) = use_aead(version, |aead| Ok(aead.expansion())) {
pub fn expansion(quic_version: QuicVersion) -> usize {
if let Ok(ex) = use_aead(quic_version, |aead| Ok(aead.expansion())) {
ex
} else {
panic!("Unable to access Retry AEAD")

View File

@ -539,9 +539,6 @@ pub struct Path {
received_bytes: usize,
/// The number of bytes sent on this path.
sent_bytes: usize,
/// For logging of events.
qlog: NeqoQlog,
}
impl Path {
@ -555,7 +552,7 @@ impl Path {
now: Instant,
) -> Self {
let mut sender = PacketSender::new(cc, Self::mtu_by_addr(remote.ip()), now);
sender.set_qlog(qlog.clone());
sender.set_qlog(qlog);
Self {
local,
remote,
@ -569,7 +566,6 @@ impl Path {
sender,
received_bytes: 0,
sent_bytes: 0,
qlog,
}
}
@ -932,27 +928,7 @@ impl Path {
}
/// Discard a packet that previously might have been in-flight.
pub fn discard_packet(&mut self, sent: &SentPacket, now: Instant) {
if self.rtt.first_sample_time().is_none() {
// When discarding a packet there might not be a good RTT estimate.
// But discards only occur after receiving something, so that means
// that there is some RTT information, which is better than nothing.
// Two cases: 1. at the client when handling a Retry and
// 2. at the server when disposing the Initial packet number space.
qinfo!(
[self],
"discarding a packet without an RTT estimate; guessing RTT={:?}",
now - sent.time_sent
);
self.rtt.update(
&mut self.qlog,
now - sent.time_sent,
Duration::new(0, 0),
false,
now,
);
}
pub fn discard_packet(&mut self, sent: &SentPacket) {
self.sender.discard(sent);
}

View File

@ -22,7 +22,7 @@ use crate::path::PathRef;
use crate::stream_id::StreamType as NeqoStreamType;
use crate::tparams::{self, TransportParametersHandler};
use crate::tracking::SentPacket;
use crate::Version;
use crate::QuicVersion;
pub fn connection_tparams_set(qlog: &mut NeqoQlog, tph: &TransportParametersHandler) {
qlog.add_event(|| {
@ -98,7 +98,7 @@ fn connection_started(qlog: &mut NeqoQlog, path: &PathRef) {
Some("QUIC".into()),
p.local_address().port().into(),
p.remote_address().port().into(),
Some(format!("{:x}", Version::default().wire_version())),
Some(format!("{:x}", QuicVersion::default().as_u32())),
Some(format!("{}", p.local_cid())),
Some(format!("{}", p.remote_cid())),
))
@ -110,7 +110,7 @@ pub fn connection_state_updated(qlog: &mut NeqoQlog, new: &State) {
Some(Event::connection_state_updated_min(match new {
State::Init => qlog::ConnectionState::Attempted,
State::WaitInitial => qlog::ConnectionState::Attempted,
State::WaitVersion | State::Handshaking => qlog::ConnectionState::Handshake,
State::Handshaking => qlog::ConnectionState::Handshake,
State::Connected => qlog::ConnectionState::Active,
State::Confirmed => qlog::ConnectionState::Active,
State::Closing { .. } => qlog::ConnectionState::Draining,

View File

@ -14,6 +14,7 @@ use neqo_common::Encoder;
use std::cmp::min;
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::ops::Deref;
pub const MAX_QUIC_DATAGRAM: u64 = 65535;
@ -52,9 +53,10 @@ impl QuicDatagram {
}
}
impl AsRef<[u8]> for QuicDatagram {
impl Deref for QuicDatagram {
type Target = [u8];
#[must_use]
fn as_ref(&self) -> &[u8] {
fn deref(&self) -> &[u8] {
&self.data[..]
}
}
@ -108,17 +110,17 @@ impl QuicDatagrams {
stats: &mut Stats,
) {
while let Some(dgram) = self.datagrams.pop_front() {
let len = dgram.as_ref().len();
let len = dgram.len();
if builder.remaining() > len {
// We need 1 more than `len` for the Frame type.
let length_len = Encoder::varint_len(u64::try_from(len).unwrap());
// Include a length if there is space for another frame after this one.
if builder.remaining() >= 1 + length_len + len + PacketBuilder::MINIMUM_FRAME_SIZE {
builder.encode_varint(FRAME_TYPE_DATAGRAM_WITH_LEN);
builder.encode_vvec(dgram.as_ref());
builder.encode_vvec(&dgram);
} else {
builder.encode_varint(FRAME_TYPE_DATAGRAM);
builder.encode(dgram.as_ref());
builder.encode(&dgram);
builder.mark_full();
}
debug_assert!(builder.len() <= builder.limit());

View File

@ -590,7 +590,7 @@ impl LossRecovery {
self.qlog = qlog;
}
pub fn drop_0rtt(&mut self, primary_path: &PathRef, now: Instant) -> Vec<SentPacket> {
pub fn drop_0rtt(&mut self, primary_path: &PathRef) -> Vec<SentPacket> {
// The largest acknowledged or loss_time should still be unset.
// The client should not have received any ACK frames when it drops 0-RTT.
assert!(self
@ -607,7 +607,7 @@ impl LossRecovery {
.collect::<Vec<_>>();
let mut path = primary_path.borrow_mut();
for p in &mut dropped {
path.discard_packet(p, now);
path.discard_packet(p);
}
dropped
}
@ -737,7 +737,7 @@ impl LossRecovery {
/// When receiving a retry, get all the sent packets so that they can be flushed.
/// We also need to pretend that they never happened for the purposes of congestion control.
pub fn retry(&mut self, primary_path: &PathRef, now: Instant) -> Vec<SentPacket> {
pub fn retry(&mut self, primary_path: &PathRef) -> Vec<SentPacket> {
self.pto_state = None;
let mut dropped = self
.spaces
@ -746,7 +746,7 @@ impl LossRecovery {
.collect::<Vec<_>>();
let mut path = primary_path.borrow_mut();
for p in &mut dropped {
path.discard_packet(p, now);
path.discard_packet(p);
}
dropped
}
@ -779,7 +779,7 @@ impl LossRecovery {
qdebug!([self], "Reset loss recovery state for {}", space);
let mut path = primary_path.borrow_mut();
for p in self.spaces.drop_space(space) {
path.discard_packet(&p, now);
path.discard_packet(&p);
}
// We just made progress, so discard PTO count.
@ -1494,25 +1494,6 @@ mod tests {
#[test]
fn rearm_pto_after_confirmed() {
let mut lr = Fixture::default();
lr.on_packet_sent(SentPacket::new(
PacketType::Initial,
0,
now(),
true,
Vec::new(),
ON_SENT_SIZE,
));
// Set the RTT to the initial value so that discarding doesn't
// alter the estimate.
let rtt = lr.path.borrow().rtt().estimate();
lr.on_ack_received(
PacketNumberSpace::Initial,
0,
vec![0..=0],
Duration::new(0, 0),
now() + rtt,
);
lr.on_packet_sent(SentPacket::new(
PacketType::Handshake,
0,

View File

@ -1966,10 +1966,7 @@ mod tests {
&mut tokens,
&mut stats,
);
qtrace!(
"STREAM frame: {}",
hex_with_len(&builder.as_ref()[header_len..])
);
qtrace!("STREAM frame: {}", hex_with_len(&builder[header_len..]));
stats.stream > 0
}

View File

@ -20,7 +20,7 @@ use crate::addr_valid::{AddressValidation, AddressValidationResult};
use crate::cid::{ConnectionId, ConnectionIdDecoder, ConnectionIdGenerator, ConnectionIdRef};
use crate::connection::{Connection, Output, State};
use crate::packet::{PacketBuilder, PacketType, PublicPacket};
use crate::{ConnectionParameters, Res, Version};
use crate::{ConnectionParameters, QuicVersion, Res};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet, VecDeque};
@ -109,7 +109,7 @@ struct InitialDetails {
src_cid: ConnectionId,
dst_cid: ConnectionId,
token: Vec<u8>,
version: Version,
quic_version: QuicVersion,
}
impl InitialDetails {
@ -118,7 +118,7 @@ impl InitialDetails {
src_cid: ConnectionId::from(packet.scid()),
dst_cid: ConnectionId::from(packet.dcid()),
token: packet.token().to_vec(),
version: packet.version().unwrap(),
quic_version: packet.version().unwrap(),
}
}
}
@ -339,7 +339,7 @@ impl Server {
};
if let Some(new_dcid) = self.cid_generator.borrow_mut().generate_cid() {
let packet = PacketBuilder::retry(
initial.version,
initial.quic_version,
&initial.src_cid,
&new_dcid,
&token,
@ -478,13 +478,11 @@ impl Server {
saved_cids: Vec::new(),
}));
let mut params = self.conn_params.clone();
params.get_versions_mut().set_initial(initial.version);
let sconn = Connection::new_server(
&self.certs,
&self.protocols,
Rc::clone(&cid_mgr) as _,
params,
self.conn_params.quic_version(initial.quic_version),
);
if let Ok(mut c) = sconn {
@ -556,29 +554,6 @@ impl Server {
return None;
}
if packet.packet_type() == PacketType::OtherVersion
|| (packet.packet_type() == PacketType::Initial
&& !self
.conn_params
.get_versions()
.all()
.contains(&packet.version().unwrap()))
{
if dgram.len() < MIN_INITIAL_PACKET_SIZE {
qdebug!([self], "Unsupported version: too short");
return None;
}
qdebug!([self], "Unsupported version: {:x}", packet.wire_version());
let vn = PacketBuilder::version_negotiation(
packet.scid(),
packet.dcid(),
packet.wire_version(),
self.conn_params.get_versions().all(),
);
return Some(Datagram::new(dgram.destination(), dgram.source(), vn));
}
match packet.packet_type() {
PacketType::Initial => {
if dgram.len() < MIN_INITIAL_PACKET_SIZE {
@ -593,7 +568,14 @@ impl Server {
let dcid = ConnectionId::from(packet.dcid());
self.handle_0rtt(dgram, dcid, now)
}
PacketType::OtherVersion => unreachable!(),
PacketType::OtherVersion => {
if dgram.len() < MIN_INITIAL_PACKET_SIZE {
qdebug!([self], "Unsupported version: too short");
return None;
}
let vn = PacketBuilder::version_negotiation(packet.scid(), packet.dcid());
Some(Datagram::new(dgram.destination(), dgram.source(), vn))
}
_ => {
qtrace!([self], "Not an initial packet");
None

View File

@ -9,13 +9,12 @@
use crate::cid::{
ConnectionId, ConnectionIdEntry, CONNECTION_ID_SEQNO_PREFERRED, MAX_CONNECTION_ID_LEN,
};
use crate::version::{Version, VersionConfig, WireVersion};
use crate::{Error, Res};
use neqo_common::{hex, qdebug, qinfo, qtrace, Decoder, Encoder, Role};
use neqo_common::{hex, qdebug, qinfo, qtrace, Decoder, Encoder};
use neqo_crypto::constants::{TLS_HS_CLIENT_HELLO, TLS_HS_ENCRYPTED_EXTENSIONS};
use neqo_crypto::ext::{ExtensionHandler, ExtensionHandlerResult, ExtensionWriterResult};
use neqo_crypto::{random, HandshakeMessage, ZeroRttCheckResult, ZeroRttChecker};
use neqo_crypto::{HandshakeMessage, ZeroRttCheckResult, ZeroRttChecker};
use std::cell::RefCell;
use std::collections::HashMap;
@ -27,10 +26,6 @@ pub type TransportParameterId = u64;
macro_rules! tpids {
{ $($n:ident = $v:expr),+ $(,)? } => {
$(pub const $n: TransportParameterId = $v as TransportParameterId;)+
/// A complete list of internal transport parameters.
#[cfg(not(test))]
pub(crate) const INTERNAL_TRANSPORT_PARAMETERS: &[TransportParameterId] = &[ $($n),+ ];
};
}
tpids! {
@ -54,7 +49,6 @@ tpids! {
GREASE_QUIC_BIT = 0x2ab2,
MIN_ACK_DELAY = 0xff02_de1a,
MAX_DATAGRAM_FRAME_SIZE = 0x0020,
VERSION_NEGOTIATION = 0xff73db,
}
#[derive(Clone, Debug, Copy)]
@ -111,10 +105,6 @@ pub enum TransportParameter {
cid: ConnectionId,
srt: [u8; 16],
},
Versions {
current: WireVersion,
other: Vec<WireVersion>,
},
}
impl TransportParameter {
@ -161,14 +151,6 @@ impl TransportParameter {
enc_inner.encode(&srt[..]);
});
}
Self::Versions { current, other } => {
enc.encode_vvec_with(|enc_inner| {
enc_inner.encode_uint(4, *current);
for v in other {
enc_inner.encode_uint(4, *v);
}
});
}
};
}
@ -217,26 +199,6 @@ impl TransportParameter {
Ok(Self::PreferredAddress { v4, v6, cid, srt })
}
fn decode_versions(dec: &mut Decoder) -> Res<Self> {
fn dv(dec: &mut Decoder) -> Res<WireVersion> {
let v = dec.decode_uint(4).ok_or(Error::NoMoreData)?;
if v == 0 {
Err(Error::TransportParameterError)
} else {
Ok(v as WireVersion)
}
}
let current = dv(dec)?;
// This rounding down is OK because `decode` checks for left over data.
let count = dec.remaining() / 4;
let mut other = Vec::with_capacity(count);
for _ in 0..count {
other.push(dv(dec)?);
}
Ok(Self::Versions { current, other })
}
fn decode(dec: &mut Decoder) -> Res<Option<(TransportParameterId, Self)>> {
let tp = dec.decode_varint().ok_or(Error::NoMoreData)?;
let content = dec.decode_vvec().ok_or(Error::NoMoreData)?;
@ -291,8 +253,6 @@ impl TransportParameter {
_ => return Err(Error::TransportParameterError),
},
VERSION_NEGOTIATION => Self::decode_versions(&mut d)?,
// Skip.
_ => return Ok(None),
};
@ -428,37 +388,6 @@ impl TransportParameters {
}
}
/// Set version information.
pub fn set_versions(&mut self, role: Role, versions: &VersionConfig) {
let rbuf = random(4);
let mut other = Vec::with_capacity(versions.all().len() + 1);
let mut dec = Decoder::new(&rbuf);
let grease = (dec.decode_uint(4).unwrap() as u32) & 0xf0f0_f0f0 | 0x0a0a0a0a;
other.push(grease);
for &v in versions.all() {
if role == Role::Client && !versions.initial().is_compatible(v) {
continue;
}
other.push(v.wire_version());
}
let current = versions.initial().wire_version();
self.set(
VERSION_NEGOTIATION,
TransportParameter::Versions { current, other },
);
}
fn compatible_upgrade(&mut self, v: Version) {
if let Some(TransportParameter::Versions {
ref mut current, ..
}) = self.params.get_mut(&VERSION_NEGOTIATION)
{
*current = v.wire_version();
} else {
unreachable!("Compatible upgrade without transport parameters set!");
}
}
pub fn get_empty(&self, tipe: TransportParameterId) -> bool {
match self.params.get(&tipe) {
None => false,
@ -487,30 +416,23 @@ impl TransportParameters {
) {
continue;
}
let ok = if let Some(v_self) = self.params.get(k) {
if let Some(v_self) = self.params.get(k) {
match (v_self, v_rem) {
(TransportParameter::Integer(i_self), TransportParameter::Integer(i_rem)) => {
if *k == MIN_ACK_DELAY {
// MIN_ACK_DELAY is backwards:
// it can only be reduced safely.
*i_self <= *i_rem
} else {
*i_self >= *i_rem
if *i_self > *i_rem {
return false;
}
} else if *i_self < *i_rem {
return false;
}
}
(TransportParameter::Empty, TransportParameter::Empty) => true,
(
TransportParameter::Versions {
current: v_self, ..
},
TransportParameter::Versions { current: v_rem, .. },
) => v_self == v_rem,
_ => false,
(TransportParameter::Empty, TransportParameter::Empty) => {}
_ => return false,
}
} else {
false
};
if !ok {
return false;
}
}
@ -532,117 +454,26 @@ impl TransportParameters {
}
}
/// Get the version negotiation values for validation.
#[must_use]
pub fn get_versions(&self) -> Option<(WireVersion, &[WireVersion])> {
if let Some(TransportParameter::Versions { current, other }) =
self.params.get(&VERSION_NEGOTIATION)
{
Some((*current, other))
} else {
None
}
}
#[must_use]
pub fn has_value(&self, tp: TransportParameterId) -> bool {
self.params.contains_key(&tp)
}
}
#[derive(Debug)]
#[derive(Default, Debug)]
pub struct TransportParametersHandler {
role: Role,
versions: VersionConfig,
pub(crate) local: TransportParameters,
pub(crate) remote: Option<TransportParameters>,
pub(crate) remote_0rtt: Option<TransportParameters>,
}
impl TransportParametersHandler {
pub fn new(role: Role, versions: VersionConfig) -> Self {
let mut local = TransportParameters::default();
local.set_versions(role, &versions);
Self {
role,
versions,
local,
remote: None,
remote_0rtt: None,
}
}
/// When resuming, the version is set based on the ticket.
/// That needs to be done to override the default choice from configuration.
pub fn set_version(&mut self, version: Version) {
debug_assert_eq!(self.role, Role::Client);
self.versions.set_initial(version);
self.local.set_versions(self.role, &self.versions)
}
pub fn remote(&self) -> &TransportParameters {
match (self.remote.as_ref(), self.remote_0rtt.as_ref()) {
(Some(tp), _) | (_, Some(tp)) => tp,
_ => panic!("no transport parameters from peer"),
}
}
/// Get the version as set (or as determined by a compatible upgrade).
pub fn version(&self) -> Version {
self.versions.initial()
}
fn compatible_upgrade(&mut self, remote_tp: &TransportParameters) -> Res<()> {
if let Some((current, other)) = remote_tp.get_versions() {
qtrace!(
"Peer versions: {:x} {:x?}; config {:?}",
current,
other,
self.versions,
);
if self.role == Role::Client {
let chosen = Version::try_from(current)?;
if self.versions.compatible().any(|&v| v == chosen) {
Ok(())
} else {
qinfo!(
"Chosen version {:x} is not compatible with initial version {:x}",
current,
self.versions.initial().wire_version(),
);
Err(Error::TransportParameterError)
}
} else {
if current != self.versions.initial().wire_version() {
qinfo!(
"Current version {:x} != own version {:x}",
current,
self.versions.initial().wire_version(),
);
return Err(Error::TransportParameterError);
}
if let Some(preferred) = self.versions.preferred_compatible(other) {
if preferred != self.versions.initial() {
qinfo!(
"Compatible upgrade {:?} ==> {:?}",
self.versions.initial(),
preferred
);
self.versions.set_initial(preferred);
self.local.compatible_upgrade(preferred);
}
Ok(())
} else {
qinfo!("Unable to find any compatible version");
Err(Error::TransportParameterError)
}
}
} else {
Ok(())
}
}
}
impl ExtensionHandler for TransportParametersHandler {
@ -657,7 +488,7 @@ impl ExtensionHandler for TransportParametersHandler {
let mut enc = Encoder::default();
self.local.encode(&mut enc);
assert!(enc.len() <= d.len());
d[..enc.len()].copy_from_slice(enc.as_ref());
d[..enc.len()].copy_from_slice(&enc);
ExtensionWriterResult::Write(enc.len())
}
@ -675,12 +506,8 @@ impl ExtensionHandler for TransportParametersHandler {
let mut dec = Decoder::from(d);
match TransportParameters::decode(&mut dec) {
Ok(tp) => {
if self.compatible_upgrade(&tp).is_ok() {
self.remote = Some(tp);
ExtensionHandlerResult::Ok
} else {
ExtensionHandlerResult::Alert(47)
}
self.remote = Some(tp);
ExtensionHandlerResult::Ok
}
_ => ExtensionHandlerResult::Alert(47), // illegal_parameter
}
@ -742,6 +569,7 @@ where
}
}
// TODO(ekr@rtfm.com): Need to write more TP unit tests.
#[cfg(test)]
#[allow(unused_variables)]
mod tests {
@ -811,7 +639,7 @@ mod tests {
let spa = make_spa();
let mut enc = Encoder::new();
spa.encode(&mut enc, PREFERRED_ADDRESS);
assert_eq!(enc.as_ref(), ENCODED);
assert_eq!(&enc[..], ENCODED);
let mut dec = enc.as_decoder();
let (id, decoded) = TransportParameter::decode(&mut dec).unwrap().unwrap();
@ -905,7 +733,7 @@ mod tests {
let spa = make_spa();
let mut enc = Encoder::new();
spa.encode(&mut enc, PREFERRED_ADDRESS);
let mut dec = Decoder::from(&enc.as_ref()[..enc.len() - 1]);
let mut dec = Decoder::from(&enc[..enc.len() - 1]);
assert_eq!(
TransportParameter::decode(&mut dec).unwrap_err(),
Error::NoMoreData
@ -1083,97 +911,4 @@ mod tests {
let invalid_decode_result = TransportParameters::decode(&mut enc.as_decoder());
assert!(invalid_decode_result.is_err());
}
#[test]
fn versions_encode_decode() {
const ENCODED: &[u8] = &[
0x80, 0xff, 0x73, 0xdb, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a,
0x6a, 0x7a, 0x8a,
];
let vn = TransportParameter::Versions {
current: Version::Version1.wire_version(),
other: vec![0x1a2a_3a4a, 0x5a6a_7a8a],
};
let mut enc = Encoder::new();
vn.encode(&mut enc, VERSION_NEGOTIATION);
assert_eq!(enc.as_ref(), ENCODED);
let mut dec = enc.as_decoder();
let (id, decoded) = TransportParameter::decode(&mut dec).unwrap().unwrap();
assert_eq!(id, VERSION_NEGOTIATION);
assert_eq!(decoded, vn);
}
#[test]
fn versions_truncated() {
const TRUNCATED: &[u8] = &[
0x80, 0xff, 0x73, 0xdb, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a,
0x6a, 0x7a,
];
let mut dec = Decoder::from(&TRUNCATED);
assert_eq!(
TransportParameter::decode(&mut dec).unwrap_err(),
Error::NoMoreData
);
}
#[test]
fn versions_zero() {
const ZERO1: &[u8] = &[0x80, 0xff, 0x73, 0xdb, 0x04, 0x00, 0x00, 0x00, 0x00];
const ZERO2: &[u8] = &[
0x80, 0xff, 0x73, 0xdb, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
];
let mut dec = Decoder::from(&ZERO1);
assert_eq!(
TransportParameter::decode(&mut dec).unwrap_err(),
Error::TransportParameterError
);
let mut dec = Decoder::from(&ZERO2);
assert_eq!(
TransportParameter::decode(&mut dec).unwrap_err(),
Error::TransportParameterError
);
}
#[test]
fn versions_equal_0rtt() {
let mut current = TransportParameters::default();
current.set(
VERSION_NEGOTIATION,
TransportParameter::Versions {
current: Version::Version1.wire_version(),
other: vec![0x1a2a_3a4a],
},
);
let mut remembered = TransportParameters::default();
// It's OK to not remember having versions.
assert!(current.ok_for_0rtt(&remembered));
// But it is bad in the opposite direction.
assert!(!remembered.ok_for_0rtt(&current));
// If the version matches, it's OK to use 0-RTT.
remembered.set(
VERSION_NEGOTIATION,
TransportParameter::Versions {
current: Version::Version1.wire_version(),
other: vec![0x5a6a_7a8a, 0x9aaa_baca],
},
);
assert!(current.ok_for_0rtt(&remembered));
assert!(remembered.ok_for_0rtt(&current));
// An apparent "upgrade" is still cause to reject 0-RTT.
remembered.set(
VERSION_NEGOTIATION,
TransportParameter::Versions {
current: Version::Version1.wire_version() + 1,
other: vec![],
},
);
assert!(!current.ok_for_0rtt(&remembered));
assert!(!remembered.ok_for_0rtt(&current));
}
}

View File

@ -26,8 +26,8 @@ use std::mem;
use std::ops::Range;
use std::rc::Rc;
/// Create a server. This is different than the one in the fixture, which is a single connection.
pub fn new_server(params: ConnectionParameters) -> Server {
// Different than the one in the fixture, which is a single connection.
pub fn default_server() -> Server {
Server::new(
now(),
test_fixture::DEFAULT_KEYS,
@ -35,16 +35,11 @@ pub fn new_server(params: ConnectionParameters) -> Server {
test_fixture::anti_replay(),
Box::new(AllowZeroRtt {}),
Rc::new(RefCell::new(CountingConnectionIdGenerator::default())),
params,
ConnectionParameters::default(),
)
.expect("should create a server")
}
/// Create a server. This is different than the one in the fixture, which is a single connection.
pub fn default_server() -> Server {
new_server(ConnectionParameters::default())
}
// Check that there is at least one connection. Returns a ref to the first confirmed connection.
pub fn connected_server(server: &mut Server) -> ActiveConnectionRef {
let server_connections = server.active_connections();
@ -115,8 +110,7 @@ pub fn decode_initial_header(dgram: &Datagram) -> (&[u8], &[u8], &[u8], &[u8]) {
)
}
/// Generate an AEAD and header protection object for a client Initial.
/// Note that this works for QUIC version 1 only.
// Generate an AEAD and header protection object for a client Initial.
#[must_use]
pub fn client_initial_aead_and_hp(dcid: &[u8]) -> (Aead, HpKey) {
const INITIAL_SALT: &[u8] = &[
@ -190,9 +184,15 @@ pub fn apply_header_protection(hp: &HpKey, packet: &mut [u8], pn_bytes: Range<us
}
}
/// Scrub through client events to find a resumption token.
pub fn find_ticket(client: &mut Connection) -> ResumptionToken {
client
pub fn get_ticket(server: &mut Server) -> ResumptionToken {
let mut client = default_client();
let mut server_conn = connect(&mut client, server);
server_conn.borrow_mut().send_ticket(now(), &[]).unwrap();
let dgram = server.process(None, now()).dgram();
client.process_input(dgram.unwrap(), now()); // Consume ticket, ignore output.
let ticket = client
.events()
.find_map(|e| {
if let ConnectionEvent::ResumptionToken(token) = e {
@ -201,18 +201,7 @@ pub fn find_ticket(client: &mut Connection) -> ResumptionToken {
None
}
})
.unwrap()
}
/// Connect to the server and have it generate a ticket.
pub fn generate_ticket(server: &mut Server) -> ResumptionToken {
let mut client = default_client();
let mut server_conn = connect(&mut client, server);
server_conn.borrow_mut().send_ticket(now(), &[]).unwrap();
let dgram = server.process(None, now()).dgram();
client.process_input(dgram.unwrap(), now()); // Consume ticket, ignore output.
let ticket = find_ticket(&mut client);
.unwrap();
// Have the client close the connection and then let the server clean up.
client.close(now(), 0, "got a ticket");

View File

@ -10,91 +10,13 @@
use neqo_common::Datagram;
use neqo_transport::{
Connection, ConnectionParameters, RandomConnectionIdGenerator, State, Version,
Connection, ConnectionParameters, QuicVersion, RandomConnectionIdGenerator, State,
};
use test_fixture::{self, addr, now};
use std::cell::RefCell;
use std::rc::Rc;
const INITIAL_PACKET_V2: &[u8] = &[
0xdd, 0x70, 0x9a, 0x50, 0xc4, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x00, 0x00,
0x44, 0x9e, 0x43, 0x91, 0xd8, 0x48, 0x23, 0xb8, 0xe6, 0x10, 0x58, 0x9c, 0x83, 0xc9, 0x2d, 0x0e,
0x97, 0xeb, 0x7a, 0x6e, 0x50, 0x03, 0xf5, 0x77, 0x64, 0xc5, 0xc7, 0xf0, 0x09, 0x5b, 0xa5, 0x4b,
0x90, 0x81, 0x8f, 0x1b, 0xfe, 0xec, 0xc1, 0xc9, 0x7c, 0x54, 0xfc, 0x73, 0x1e, 0xdb, 0xd2, 0xa2,
0x44, 0xe3, 0xb1, 0xe6, 0x39, 0xa9, 0xbc, 0x75, 0xed, 0x54, 0x5b, 0x98, 0x64, 0x93, 0x43, 0xb2,
0x53, 0x61, 0x5e, 0xc6, 0xb3, 0xe4, 0xdf, 0x0f, 0xd2, 0xe7, 0xfe, 0x9d, 0x69, 0x1a, 0x09, 0xe6,
0xa1, 0x44, 0xb4, 0x36, 0xd8, 0xa2, 0xc0, 0x88, 0xa4, 0x04, 0x26, 0x23, 0x40, 0xdf, 0xd9, 0x95,
0xec, 0x38, 0x65, 0x69, 0x4e, 0x30, 0x26, 0xec, 0xd8, 0xc6, 0xd2, 0x56, 0x1a, 0x5a, 0x36, 0x67,
0x2a, 0x10, 0x05, 0x01, 0x81, 0x68, 0xc0, 0xf0, 0x81, 0xc1, 0x0e, 0x2b, 0xf1, 0x4d, 0x55, 0x0c,
0x97, 0x7e, 0x28, 0xbb, 0x9a, 0x75, 0x9c, 0x57, 0xd0, 0xf7, 0xff, 0xb1, 0xcd, 0xfb, 0x40, 0xbd,
0x77, 0x4d, 0xec, 0x58, 0x96, 0x57, 0x54, 0x20, 0x47, 0xdf, 0xfe, 0xfa, 0x56, 0xfc, 0x80, 0x89,
0xa4, 0xd1, 0xef, 0x37, 0x9c, 0x81, 0xba, 0x3d, 0xf7, 0x1a, 0x05, 0xdd, 0xc7, 0x92, 0x83, 0x40,
0x77, 0x59, 0x10, 0xfe, 0xb3, 0xce, 0x4c, 0xbc, 0xfd, 0x8d, 0x25, 0x3e, 0xdd, 0x05, 0xf1, 0x61,
0x45, 0x8f, 0x9d, 0xc4, 0x4b, 0xea, 0x01, 0x7c, 0x31, 0x17, 0xcc, 0xa7, 0x06, 0x5a, 0x31, 0x5d,
0xed, 0xa9, 0x46, 0x4e, 0x67, 0x2e, 0xc8, 0x0c, 0x3f, 0x79, 0xac, 0x99, 0x34, 0x37, 0xb4, 0x41,
0xef, 0x74, 0x22, 0x7e, 0xcc, 0x4d, 0xc9, 0xd5, 0x97, 0xf6, 0x6a, 0xb0, 0xab, 0x8d, 0x21, 0x4b,
0x55, 0x84, 0x0c, 0x70, 0x34, 0x9d, 0x76, 0x16, 0xcb, 0xe3, 0x8e, 0x5e, 0x1d, 0x05, 0x2d, 0x07,
0xf1, 0xfe, 0xdb, 0x3d, 0xd3, 0xc4, 0xd8, 0xce, 0x29, 0x57, 0x24, 0x94, 0x5e, 0x67, 0xed, 0x2e,
0xef, 0xcd, 0x9f, 0xb5, 0x24, 0x72, 0x38, 0x7f, 0x31, 0x8e, 0x3d, 0x9d, 0x23, 0x3b, 0xe7, 0xdf,
0xc7, 0x9d, 0x6b, 0xf6, 0x08, 0x0d, 0xcb, 0xbb, 0x41, 0xfe, 0xb1, 0x80, 0xd7, 0x85, 0x88, 0x49,
0x7c, 0x3e, 0x43, 0x9d, 0x38, 0xc3, 0x34, 0x74, 0x8d, 0x2b, 0x56, 0xfd, 0x19, 0xab, 0x36, 0x4d,
0x05, 0x7a, 0x9b, 0xd5, 0xa6, 0x99, 0xae, 0x14, 0x5d, 0x7f, 0xdb, 0xc8, 0xf5, 0x77, 0x75, 0x18,
0x1b, 0x0a, 0x97, 0xc3, 0xbd, 0xed, 0xc9, 0x1a, 0x55, 0x5d, 0x6c, 0x9b, 0x86, 0x34, 0xe1, 0x06,
0xd8, 0xc9, 0xca, 0x45, 0xa9, 0xd5, 0x45, 0x0a, 0x76, 0x79, 0xed, 0xc5, 0x45, 0xda, 0x91, 0x02,
0x5b, 0xc9, 0x3a, 0x7c, 0xf9, 0xa0, 0x23, 0xa0, 0x66, 0xff, 0xad, 0xb9, 0x71, 0x7f, 0xfa, 0xf3,
0x41, 0x4c, 0x3b, 0x64, 0x6b, 0x57, 0x38, 0xb3, 0xcc, 0x41, 0x16, 0x50, 0x2d, 0x18, 0xd7, 0x9d,
0x82, 0x27, 0x43, 0x63, 0x06, 0xd9, 0xb2, 0xb3, 0xaf, 0xc6, 0xc7, 0x85, 0xce, 0x3c, 0x81, 0x7f,
0xeb, 0x70, 0x3a, 0x42, 0xb9, 0xc8, 0x3b, 0x59, 0xf0, 0xdc, 0xef, 0x12, 0x45, 0xd0, 0xb3, 0xe4,
0x02, 0x99, 0x82, 0x1e, 0xc1, 0x95, 0x49, 0xce, 0x48, 0x97, 0x14, 0xfe, 0x26, 0x11, 0xe7, 0x2c,
0xd8, 0x82, 0xf4, 0xf7, 0x0d, 0xce, 0x7d, 0x36, 0x71, 0x29, 0x6f, 0xc0, 0x45, 0xaf, 0x5c, 0x9f,
0x63, 0x0d, 0x7b, 0x49, 0xa3, 0xeb, 0x82, 0x1b, 0xbc, 0xa6, 0x0f, 0x19, 0x84, 0xdc, 0xe6, 0x64,
0x91, 0x71, 0x3b, 0xfe, 0x06, 0x00, 0x1a, 0x56, 0xf5, 0x1b, 0xb3, 0xab, 0xe9, 0x2f, 0x79, 0x60,
0x54, 0x7c, 0x4d, 0x0a, 0x70, 0xf4, 0xa9, 0x62, 0xb3, 0xf0, 0x5d, 0xc2, 0x5a, 0x34, 0xbb, 0xe8,
0x30, 0xa7, 0xea, 0x47, 0x36, 0xd3, 0xb0, 0x16, 0x17, 0x23, 0x50, 0x0d, 0x82, 0xbe, 0xda, 0x9b,
0xe3, 0x32, 0x7a, 0xf2, 0xaa, 0x41, 0x38, 0x21, 0xff, 0x67, 0x8b, 0x2a, 0x87, 0x6e, 0xc4, 0xb0,
0x0b, 0xb6, 0x05, 0xff, 0xcc, 0x39, 0x17, 0xff, 0xdc, 0x27, 0x9f, 0x18, 0x7d, 0xaa, 0x2f, 0xce,
0x8c, 0xde, 0x12, 0x19, 0x80, 0xbb, 0xa8, 0xec, 0x8f, 0x44, 0xca, 0x56, 0x2b, 0x0f, 0x13, 0x19,
0x14, 0xc9, 0x01, 0xcf, 0xbd, 0x84, 0x74, 0x08, 0xb7, 0x78, 0xe6, 0x73, 0x8c, 0x7b, 0xb5, 0xb1,
0xb3, 0xf9, 0x7d, 0x01, 0xb0, 0xa2, 0x4d, 0xcc, 0xa4, 0x0e, 0x3b, 0xed, 0x29, 0x41, 0x1b, 0x1b,
0xa8, 0xf6, 0x08, 0x43, 0xc4, 0xa2, 0x41, 0x02, 0x1b, 0x23, 0x13, 0x2b, 0x95, 0x00, 0x50, 0x9b,
0x9a, 0x35, 0x16, 0xd4, 0xa9, 0xdd, 0x41, 0xd3, 0xba, 0xcb, 0xcd, 0x42, 0x6b, 0x45, 0x13, 0x93,
0x52, 0x18, 0x28, 0xaf, 0xed, 0xcf, 0x20, 0xfa, 0x46, 0xac, 0x24, 0xf4, 0x4a, 0x8e, 0x29, 0x73,
0x30, 0xb1, 0x67, 0x05, 0xd5, 0xd5, 0xf7, 0x98, 0xef, 0xf9, 0xe9, 0x13, 0x4a, 0x06, 0x59, 0x79,
0x87, 0xa1, 0xdb, 0x46, 0x17, 0xca, 0xa2, 0xd9, 0x38, 0x37, 0x73, 0x08, 0x29, 0xd4, 0xd8, 0x9e,
0x16, 0x41, 0x3b, 0xe4, 0xd8, 0xa8, 0xa3, 0x8a, 0x7e, 0x62, 0x26, 0x62, 0x3b, 0x64, 0xa8, 0x20,
0x17, 0x8e, 0xc3, 0xa6, 0x69, 0x54, 0xe1, 0x07, 0x10, 0xe0, 0x43, 0xae, 0x73, 0xdd, 0x3f, 0xb2,
0x71, 0x5a, 0x05, 0x25, 0xa4, 0x63, 0x43, 0xfb, 0x75, 0x90, 0xe5, 0xea, 0xc7, 0xee, 0x55, 0xfc,
0x81, 0x0e, 0x0d, 0x8b, 0x4b, 0x8f, 0x7b, 0xe8, 0x2c, 0xd5, 0xa2, 0x14, 0x57, 0x5a, 0x1b, 0x99,
0x62, 0x9d, 0x47, 0xa9, 0xb2, 0x81, 0xb6, 0x13, 0x48, 0xc8, 0x62, 0x7c, 0xab, 0x38, 0xe2, 0xa6,
0x4d, 0xb6, 0x62, 0x6e, 0x97, 0xbb, 0x8f, 0x77, 0xbd, 0xcb, 0x0f, 0xee, 0x47, 0x6a, 0xed, 0xd7,
0xba, 0x8f, 0x54, 0x41, 0xac, 0xaa, 0xb0, 0x0f, 0x44, 0x32, 0xed, 0xab, 0x37, 0x91, 0x04, 0x7d,
0x90, 0x91, 0xb2, 0xa7, 0x53, 0xf0, 0x35, 0x64, 0x84, 0x31, 0xf6, 0xd1, 0x2f, 0x7d, 0x6a, 0x68,
0x1e, 0x64, 0xc8, 0x61, 0xf4, 0xac, 0x91, 0x1a, 0x0f, 0x7d, 0x6e, 0xc0, 0x49, 0x1a, 0x78, 0xc9,
0xf1, 0x92, 0xf9, 0x6b, 0x3a, 0x5e, 0x75, 0x60, 0xa3, 0xf0, 0x56, 0xbc, 0x1c, 0xa8, 0x59, 0x83,
0x67, 0xad, 0x6a, 0xcb, 0x6f, 0x2e, 0x03, 0x4c, 0x7f, 0x37, 0xbe, 0xeb, 0x9e, 0xd4, 0x70, 0xc4,
0x30, 0x4a, 0xf0, 0x10, 0x7f, 0x0e, 0xb9, 0x19, 0xbe, 0x36, 0xa8, 0x6f, 0x68, 0xf3, 0x7f, 0xa6,
0x1d, 0xae, 0x7a, 0xff, 0x14, 0xde, 0xcd, 0x67, 0xec, 0x31, 0x57, 0xa1, 0x14, 0x88, 0xa1, 0x4f,
0xed, 0x01, 0x42, 0x82, 0x83, 0x48, 0xf5, 0xf6, 0x08, 0xb0, 0xfe, 0x03, 0xe1, 0xf3, 0xc0, 0xaf,
0x3a, 0xcc, 0xa0, 0xce, 0x36, 0x85, 0x2e, 0xd4, 0x2e, 0x22, 0x0a, 0xe9, 0xab, 0xf8, 0xf8, 0x90,
0x6f, 0x00, 0xf1, 0xb8, 0x6b, 0xff, 0x85, 0x04, 0xc8, 0xf1, 0x6c, 0x78, 0x4f, 0xd5, 0x2d, 0x25,
0xe0, 0x13, 0xff, 0x4f, 0xda, 0x90, 0x3e, 0x9e, 0x1e, 0xb4, 0x53, 0xc1, 0x46, 0x4b, 0x11, 0x96,
0x6d, 0xb9, 0xb2, 0x8e, 0x8f, 0x26, 0xa3, 0xfc, 0x41, 0x9e, 0x6a, 0x60, 0xa4, 0x8d, 0x4c, 0x72,
0x14, 0xee, 0x9c, 0x6c, 0x6a, 0x12, 0xb6, 0x8a, 0x32, 0xca, 0xc8, 0xf6, 0x15, 0x80, 0xc6, 0x4f,
0x29, 0xcb, 0x69, 0x22, 0x40, 0x87, 0x83, 0xc6, 0xd1, 0x2e, 0x72, 0x5b, 0x01, 0x4f, 0xe4, 0x85,
0xcd, 0x17, 0xe4, 0x84, 0xc5, 0x95, 0x2b, 0xf9, 0x9b, 0xc9, 0x49, 0x41, 0xd4, 0xb1, 0x91, 0x9d,
0x04, 0x31, 0x7b, 0x8a, 0xa1, 0xbd, 0x37, 0x54, 0xec, 0xba, 0xa1, 0x0e, 0xc2, 0x27, 0xde, 0x85,
0x40, 0x69, 0x5b, 0xf2, 0xfb, 0x8e, 0xe5, 0x6f, 0x6d, 0xc5, 0x26, 0xef, 0x36, 0x66, 0x25, 0xb9,
0x1a, 0xa4, 0x97, 0x0b, 0x6f, 0xfa, 0x5c, 0x82, 0x84, 0xb9, 0xb5, 0xab, 0x85, 0x2b, 0x90, 0x5f,
0x9d, 0x83, 0xf5, 0x66, 0x9c, 0x05, 0x35, 0xbc, 0x37, 0x7b, 0xcc, 0x05, 0xad, 0x5e, 0x48, 0xe2,
0x81, 0xec, 0x0e, 0x19, 0x17, 0xca, 0x3c, 0x6a, 0x47, 0x1f, 0x8d, 0xa0, 0x89, 0x4b, 0xc8, 0x2a,
0xc2, 0xa8, 0x96, 0x54, 0x05, 0xd6, 0xee, 0xf3, 0xb5, 0xe2, 0x93, 0xa8, 0x8f, 0xda, 0x20, 0x3f,
0x09, 0xbd, 0xc7, 0x27, 0x57, 0xb1, 0x07, 0xab, 0x14, 0x88, 0x0e, 0xaa, 0x3e, 0xf7, 0x04, 0x5b,
0x58, 0x0f, 0x48, 0x21, 0xce, 0x6d, 0xd3, 0x25, 0xb5, 0xa9, 0x06, 0x55, 0xd8, 0xc5, 0xb5, 0x5f,
0x76, 0xfb, 0x84, 0x62, 0x79, 0xa9, 0xb5, 0x18, 0xc5, 0xe9, 0xb9, 0xa2, 0x11, 0x65, 0xc5, 0x09,
0x3e, 0xd4, 0x9b, 0xaa, 0xac, 0xad, 0xf1, 0xf2, 0x18, 0x73, 0x26, 0x6c, 0x76, 0x7f, 0x67, 0x69,
];
const INITIAL_PACKET_V1: &[u8] = &[
0xc0, 0x00, 0x00, 0x00, 0x01, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x00, 0x00,
0x44, 0x9e, 0x7b, 0x9a, 0xec, 0x34, 0xd1, 0xb1, 0xc9, 0x8d, 0xd7, 0x68, 0x9f, 0xb8, 0xec, 0x11,
@ -251,19 +173,19 @@ const INITIAL_PACKET_29: &[u8] = &[
0x18, 0x02, 0x77, 0x1a, 0x44, 0x9b, 0x30, 0xf3, 0xfa, 0x22, 0x89, 0x85, 0x26, 0x07, 0xb6, 0x60,
];
fn make_server(v: Version) -> Connection {
fn make_server(quic_version: QuicVersion) -> Connection {
test_fixture::fixture_init();
Connection::new_server(
test_fixture::DEFAULT_KEYS,
test_fixture::DEFAULT_ALPN,
Rc::new(RefCell::new(RandomConnectionIdGenerator::new(5))),
ConnectionParameters::default().versions(v, vec![v]),
ConnectionParameters::default().quic_version(quic_version),
)
.expect("create a default server")
}
fn process_client_initial(v: Version, packet: &[u8]) {
let mut server = make_server(v);
fn process_client_initial(quic_version: QuicVersion, packet: &[u8]) {
let mut server = make_server(quic_version);
let dgram = Datagram::new(addr(), addr(), packet);
assert_eq!(*server.state(), State::Init);
@ -272,17 +194,12 @@ fn process_client_initial(v: Version, packet: &[u8]) {
assert!(out.dgram().is_some());
}
#[test]
fn process_client_initial_v2() {
process_client_initial(Version::Version2, INITIAL_PACKET_V2);
}
#[test]
fn process_client_initial_v1() {
process_client_initial(Version::Version1, INITIAL_PACKET_V1);
process_client_initial(QuicVersion::Version1, INITIAL_PACKET_V1);
}
#[test]
fn process_client_initial_29() {
process_client_initial(Version::Draft29, INITIAL_PACKET_29);
process_client_initial(QuicVersion::Draft29, INITIAL_PACKET_29);
}

View File

@ -34,8 +34,8 @@ fn truncate_long_packet() {
dupe.destination(),
&dupe[..(dupe.len() - tail)],
);
let hs_probe = client.process(Some(truncated), now()).dgram();
assert!(hs_probe.is_some());
let dupe_ack = client.process(Some(truncated), now()).dgram();
assert!(dupe_ack.is_some());
// Now feed in the untruncated packet.
let dgram = client.process(dgram, now()).dgram();

View File

@ -12,7 +12,7 @@ mod common;
use common::{
apply_header_protection, client_initial_aead_and_hp, connected_server, decode_initial_header,
default_server, generate_ticket, remove_header_protection,
default_server, get_ticket, remove_header_protection,
};
use neqo_common::{hex_with_len, qdebug, qtrace, Datagram, Encoder};
use neqo_crypto::AuthenticationStatus;
@ -50,26 +50,6 @@ fn retry_basic() {
connected_server(&mut server);
}
/// Receiving a Retry is enough to infer something about the RTT.
/// Probably.
#[test]
fn implicit_rtt_retry() {
const RTT: Duration = Duration::from_secs(2);
let mut server = default_server();
server.set_validation(ValidateAddress::Always);
let mut client = default_client();
let mut now = now();
let dgram = client.process(None, now).dgram();
now += RTT / 2;
let dgram = server.process(dgram, now).dgram();
assertions::assert_retry(dgram.as_ref().unwrap());
now += RTT / 2;
client.process_input(dgram.unwrap(), now);
assert_eq!(client.stats().rtt, RTT);
}
#[test]
fn retry_expired() {
let mut server = default_server();
@ -96,7 +76,7 @@ fn retry_expired() {
#[test]
fn retry_0rtt() {
let mut server = default_server();
let token = generate_ticket(&mut server);
let token = get_ticket(&mut server);
server.set_validation(ValidateAddress::Always);
let mut client = default_client();
@ -158,7 +138,7 @@ fn retry_different_ip() {
#[test]
fn new_token_different_ip() {
let mut server = default_server();
let token = generate_ticket(&mut server);
let token = get_ticket(&mut server);
server.set_validation(ValidateAddress::NoToken);
let mut client = default_client();
@ -180,7 +160,7 @@ fn new_token_different_ip() {
#[test]
fn new_token_expired() {
let mut server = default_server();
let token = generate_ticket(&mut server);
let token = get_ticket(&mut server);
server.set_validation(ValidateAddress::NoToken);
let mut client = default_client();
@ -395,13 +375,12 @@ fn mitm_retry() {
.encode_vvec(&[])
.encode_varint(u64::try_from(payload.len()).unwrap());
let pn_offset = enc.len();
let notoken_header = enc.encode_uint(pn_len, pn).as_ref().to_vec();
let notoken_header = enc.encode_uint(pn_len, pn).to_vec();
qtrace!("notoken_header={}", hex_with_len(&notoken_header));
// Encrypt.
let mut notoken_packet = Encoder::with_capacity(1200)
.encode(&notoken_header)
.as_ref()
.to_vec();
notoken_packet.resize_with(1200, u8::default);
aead.encrypt(

View File

@ -11,21 +11,18 @@ mod common;
use common::{
apply_header_protection, client_initial_aead_and_hp, connect, connected_server,
decode_initial_header, default_server, find_ticket, generate_ticket, new_server,
remove_header_protection,
decode_initial_header, default_server, get_ticket, remove_header_protection,
};
use neqo_common::{qtrace, Datagram, Decoder, Encoder};
use neqo_crypto::{
generate_ech_keys, AllowZeroRtt, AuthenticationStatus, ZeroRttCheckResult, ZeroRttChecker,
};
use neqo_crypto::{generate_ech_keys, AllowZeroRtt, ZeroRttCheckResult, ZeroRttChecker};
use neqo_transport::{
server::{ActiveConnectionRef, Server, ValidateAddress},
Connection, ConnectionError, ConnectionParameters, Error, Output, State, StreamType, Version,
Connection, ConnectionError, ConnectionParameters, Error, Output, QuicVersion, State,
StreamType,
};
use test_fixture::{
self, assertions, default_client, new_client, now, split_datagram,
CountingConnectionIdGenerator,
self, assertions, default_client, now, split_datagram, CountingConnectionIdGenerator,
};
use std::cell::RefCell;
@ -69,70 +66,6 @@ fn single_client() {
connect(&mut client, &mut server);
}
#[test]
fn connect_single_version_both() {
fn connect_one_version(version: Version) {
let params = ConnectionParameters::default().versions(version, vec![version]);
let mut server = new_server(params.clone());
let mut client = new_client(params);
let server_conn = connect(&mut client, &mut server);
assert_eq!(client.version(), version);
assert_eq!(server_conn.borrow().version(), version);
}
for v in Version::all() {
println!("Connecting with {:?}", v);
connect_one_version(v);
}
}
#[test]
fn connect_single_version_client() {
fn connect_one_version(version: Version) {
let mut server = default_server();
let mut client =
new_client(ConnectionParameters::default().versions(version, vec![version]));
let server_conn = connect(&mut client, &mut server);
assert_eq!(client.version(), version);
assert_eq!(server_conn.borrow().version(), version);
}
for v in Version::all() {
println!("Connecting with {:?}", v);
connect_one_version(v);
}
}
#[test]
fn connect_single_version_server() {
fn connect_one_version(version: Version) {
let mut server =
new_server(ConnectionParameters::default().versions(version, vec![version]));
let mut client = default_client();
if client.version() != version {
// Run the version negotiation exchange if necessary.
let dgram = client.process_output(now()).dgram();
assert!(dgram.is_some());
let dgram = server.process(dgram, now()).dgram();
assertions::assert_vn(dgram.as_ref().unwrap());
client.process_input(dgram.unwrap(), now());
}
let server_conn = connect(&mut client, &mut server);
assert_eq!(client.version(), version);
assert_eq!(server_conn.borrow().version(), version);
}
for v in Version::all() {
println!("Connecting with {:?}", v);
connect_one_version(v);
}
}
#[test]
fn duplicate_initial() {
let mut server = default_server();
@ -231,7 +164,7 @@ fn drop_non_initial() {
let mut header = neqo_common::Encoder::with_capacity(1200);
header
.encode_byte(0xfa)
.encode_uint(4, Version::default().wire_version())
.encode_uint(4, QuicVersion::default().as_u32())
.encode_vec(1, CID)
.encode_vec(1, CID);
let mut bogus_data: Vec<u8> = header.into();
@ -250,7 +183,7 @@ fn drop_short_initial() {
let mut header = neqo_common::Encoder::with_capacity(1199);
header
.encode_byte(0xca)
.encode_uint(4, Version::default().wire_version())
.encode_uint(4, QuicVersion::default().as_u32())
.encode_vec(1, CID)
.encode_vec(1, CID);
let mut bogus_data: Vec<u8> = header.into();
@ -267,7 +200,7 @@ fn drop_short_initial() {
#[test]
fn zero_rtt() {
let mut server = default_server();
let token = generate_ticket(&mut server);
let token = get_ticket(&mut server);
// Discharge the old connection so that we don't have to worry about it.
let mut now = now();
@ -329,7 +262,7 @@ fn zero_rtt() {
#[test]
fn new_token_0rtt() {
let mut server = default_server();
let token = generate_ticket(&mut server);
let token = get_ticket(&mut server);
server.set_validation(ValidateAddress::NoToken);
let mut client = default_client();
@ -360,7 +293,7 @@ fn new_token_0rtt() {
#[test]
fn new_token_different_port() {
let mut server = default_server();
let token = generate_ticket(&mut server);
let token = get_ticket(&mut server);
server.set_validation(ValidateAddress::NoToken);
let mut client = default_client();
@ -402,20 +335,20 @@ fn bad_client_initial() {
let mut header_enc = Encoder::new();
header_enc
.encode_byte(0xc0) // Initial with 1 byte packet number.
.encode_uint(4, Version::default().wire_version())
.encode_uint(4, QuicVersion::default().as_u32())
.encode_vec(1, d_cid)
.encode_vec(1, s_cid)
.encode_vvec(&[])
.encode_varint(u64::try_from(payload_enc.len() + aead.expansion() + 1).unwrap())
.encode_byte(u8::try_from(pn).unwrap());
let mut ciphertext = header_enc.as_ref().to_vec();
let mut ciphertext = header_enc.to_vec();
ciphertext.resize(header_enc.len() + payload_enc.len() + aead.expansion(), 0);
let v = aead
.encrypt(
pn,
header_enc.as_ref(),
payload_enc.as_ref(),
&header_enc,
&payload_enc,
&mut ciphertext[header_enc.len()..],
)
.unwrap();
@ -468,7 +401,7 @@ fn bad_client_initial() {
}
#[test]
fn version_negotiation_ignored() {
fn version_negotiation() {
let mut server = default_server();
let mut client = default_client();
@ -493,7 +426,7 @@ fn version_negotiation_ignored() {
let mut found = false;
while dec.remaining() > 0 {
let v = dec.decode_uint(4).expect("supported version");
found |= v == u64::from(Version::default().wire_version());
found |= v == u64::from(QuicVersion::default().as_u32());
}
assert!(found, "valid version not found");
@ -503,128 +436,6 @@ fn version_negotiation_ignored() {
assert_eq!(client.state(), &State::WaitInitial);
}
/// Test that if the server doesn't support a version it will signal with a
/// Version Negotiation packet and the client will use that version.
#[test]
fn version_negotiation() {
const VN_VERSION: Version = Version::Draft29;
assert_ne!(VN_VERSION, Version::default());
assert!(!Version::default().is_compatible(VN_VERSION));
let mut server =
new_server(ConnectionParameters::default().versions(VN_VERSION, vec![VN_VERSION]));
let mut client = default_client();
// `connect()` runs a fixed exchange, so manually run the Version Negotiation.
let dgram = client.process_output(now()).dgram();
assert!(dgram.is_some());
let dgram = server.process(dgram, now()).dgram();
assertions::assert_vn(dgram.as_ref().unwrap());
client.process_input(dgram.unwrap(), now());
let sconn = connect(&mut client, &mut server);
assert_eq!(client.version(), VN_VERSION);
assert_eq!(sconn.borrow().version(), VN_VERSION);
}
/// Test that the client can pick a version from a Version Negotiation packet,
/// which is then subsequently upgraded to a compatible version by the server.
#[test]
fn version_negotiation_and_compatible() {
const ORIG_VERSION: Version = Version::Draft29;
const VN_VERSION: Version = Version::Version1;
const COMPAT_VERSION: Version = Version::Version2;
assert!(!ORIG_VERSION.is_compatible(VN_VERSION));
assert!(!ORIG_VERSION.is_compatible(COMPAT_VERSION));
assert!(VN_VERSION.is_compatible(COMPAT_VERSION));
let mut server = new_server(
ConnectionParameters::default().versions(VN_VERSION, vec![COMPAT_VERSION, VN_VERSION]),
);
// Note that the order of versions at the client only determines what it tries first.
// The server will pick between VN_VERSION and COMPAT_VERSION.
let mut client = new_client(
ConnectionParameters::default()
.versions(ORIG_VERSION, vec![ORIG_VERSION, VN_VERSION, COMPAT_VERSION]),
);
// Run the full exchange so that we can observe the versions in use.
// Version Negotiation
let dgram = client.process_output(now()).dgram();
assert!(dgram.is_some());
assertions::assert_version(dgram.as_ref().unwrap(), ORIG_VERSION.wire_version());
let dgram = server.process(dgram, now()).dgram();
assertions::assert_vn(dgram.as_ref().unwrap());
client.process_input(dgram.unwrap(), now());
let dgram = client.process(None, now()).dgram(); // ClientHello
assertions::assert_version(dgram.as_ref().unwrap(), VN_VERSION.wire_version());
let dgram = server.process(dgram, now()).dgram(); // ServerHello...
assertions::assert_version(dgram.as_ref().unwrap(), COMPAT_VERSION.wire_version());
client.process_input(dgram.unwrap(), now());
client.authenticated(AuthenticationStatus::Ok, now());
let dgram = client.process_output(now()).dgram();
assertions::assert_version(dgram.as_ref().unwrap(), COMPAT_VERSION.wire_version());
assert_eq!(*client.state(), State::Connected);
let dgram = server.process(dgram, now()).dgram(); // ACK + HANDSHAKE_DONE + NST
client.process_input(dgram.unwrap(), now());
assert_eq!(*client.state(), State::Confirmed);
let sconn = connected_server(&mut server);
assert_eq!(client.version(), COMPAT_VERSION);
assert_eq!(sconn.borrow().version(), COMPAT_VERSION);
}
/// When a client resumes it remembers the version that the connection last used.
/// A subsequent connection will use that version, but if it then receives
/// a version negotiation packet, it should validate based on what it attempted
/// not what it was originally configured for.
#[test]
fn compatible_upgrade_resumption_and_vn() {
// Start at v1, compatible upgrade to v2.
const ORIG_VERSION: Version = Version::Version1;
const COMPAT_VERSION: Version = Version::Version2;
const RESUMPTION_VERSION: Version = Version::Draft29;
let client_params = ConnectionParameters::default().versions(
ORIG_VERSION,
vec![COMPAT_VERSION, ORIG_VERSION, RESUMPTION_VERSION],
);
let mut client = new_client(client_params.clone());
assert_eq!(client.version(), ORIG_VERSION);
let mut server = default_server();
let mut server_conn = connect(&mut client, &mut server);
assert_eq!(client.version(), COMPAT_VERSION);
assert_eq!(server_conn.borrow().version(), COMPAT_VERSION);
server_conn.borrow_mut().send_ticket(now(), &[]).unwrap();
let dgram = server.process(None, now()).dgram();
client.process_input(dgram.unwrap(), now()); // Consume ticket, ignore output.
let ticket = find_ticket(&mut client);
// This new server will reject the ticket, but it will also generate a VN packet.
let mut client = new_client(client_params);
let mut server = new_server(
ConnectionParameters::default().versions(RESUMPTION_VERSION, vec![RESUMPTION_VERSION]),
);
client.enable_resumption(now(), ticket).unwrap();
// The version negotiation exchange.
let dgram = client.process_output(now()).dgram();
assert!(dgram.is_some());
assertions::assert_version(dgram.as_ref().unwrap(), COMPAT_VERSION.wire_version());
let dgram = server.process(dgram, now()).dgram();
assertions::assert_vn(dgram.as_ref().unwrap());
client.process_input(dgram.unwrap(), now());
let server_conn = connect(&mut client, &mut server);
assert_eq!(client.version(), RESUMPTION_VERSION);
assert_eq!(server_conn.borrow().version(), RESUMPTION_VERSION);
}
#[test]
fn closed() {
// Let a server connection idle and it should be removed.
@ -722,7 +533,7 @@ fn max_streams_after_0rtt_rejection() {
.max_streams(StreamType::UniDi, MAX_STREAMS_UNIDI),
)
.expect("should create a server");
let token = generate_ticket(&mut server);
let token = get_ticket(&mut server);
let mut client = default_client();
client.enable_resumption(now(), &token).unwrap();

View File

@ -149,7 +149,7 @@ impl Simulator {
/// Though this is convenient, it panics if this isn't a 64 character hex string.
pub fn seed_str(&mut self, seed: impl AsRef<str>) {
let seed = Encoder::from_hex(seed);
self.seed(<[u8; 32]>::try_from(seed.as_ref()).unwrap());
self.seed(<[u8; 32]>::try_from(&seed[..]).unwrap());
}
fn next_time(&self, now: Instant) -> Instant {