Skip to content

Commit

Permalink
Merge pull request #4 from kapilvgit/kapilv/upstream
Browse files Browse the repository at this point in the history
support chunked OHTTP and P384
  • Loading branch information
kapilvgit authored Oct 29, 2024
2 parents fd72888 + d5c6834 commit 1e00204
Show file tree
Hide file tree
Showing 16 changed files with 690 additions and 50 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ jobs:
fail-fast: false
matrix:
hpke:
- nss
- rust-hpke
rust:
- 1.63.0 # MSRV
- 1.75.0
- stable

steps:
Expand Down
3 changes: 3 additions & 0 deletions bhttp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ read-bhttp = []
write-bhttp = []
read-http = ["url"]
write-http = []
stream = []

[dependencies]
thiserror = "1"
url = {version = "2", optional = true}
tracing = "0.1"
backtrace = "0.3"

[dev-dependencies]
hex = "0.4"
8 changes: 8 additions & 0 deletions bhttp/src/err.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@ pub enum Error {
ExpectedResponse,
#[error("a field contained an integer value that was out of range: {0}")]
IntRange(#[from] std::num::TryFromIntError),
#[error("Invalid end of chunk. Expected zero-sized chunk")]
InvalidChunkEnd,
#[error("the mode of the message was invalid")]
InvalidMode,
#[error("the status code of a response needs to be in 100..=599")]
InvalidStatus,
#[error("IO error {0}")]
Io(#[from] std::io::Error),
#[error("Invalid uint")]
InvalidUint,
#[error("a field or line was missing a necessary character 0x{0:x}")]
Missing(u8),
#[error("a URL was missing a key component")]
Expand All @@ -31,11 +35,15 @@ pub enum Error {
ParseInt(#[from] std::num::ParseIntError),
#[error("a field was truncated")]
Truncated,
#[error("Unreachable")]
Unreachable,
#[error("a message included the Upgrade field")]
UpgradeUnsupported,
#[error("a URL could not be parsed into components: {0}")]
#[cfg(feature = "read-http")]
UrlParse(#[from] url::ParseError),
#[error("Varint value too large")]
VariantTooLarge,
}

#[cfg(any(
Expand Down
8 changes: 6 additions & 2 deletions bhttp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,9 @@ impl Message {
}
let mut buf = vec![0; count];
r.borrow_mut().read_exact(&mut buf)?;
assert!(read_line(r)?.is_empty());
if !read_line(r)?.is_empty() {
return Err(Error::InvalidChunkEnd);
}
content.append(&mut buf);
}
}
Expand Down Expand Up @@ -781,7 +783,9 @@ impl Message {
let mode = match t {
0 | 1 => Mode::KnownLength,
2 | 3 => Mode::IndeterminateLength,
_ => return Err(Error::InvalidMode),
_ => {
return Err(Error::InvalidMode);
}
};

let mut control = ControlData::read_bhttp(request, r)?;
Expand Down
10 changes: 7 additions & 3 deletions bhttp/src/rw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use crate::{err::Error, ReadSeek};
#[allow(clippy::cast_possible_truncation)]
fn write_uint(n: u8, v: impl Into<u64>, w: &mut impl io::Write) -> Res<()> {
let v = v.into();
assert!(n > 0 && usize::from(n) < std::mem::size_of::<u64>());
if !(n > 0 && usize::from(n) < std::mem::size_of::<u64>()) {
return Err(Error::InvalidUint);
}
for i in 0..n {
w.write_all(&[((v >> (8 * (n - i - 1))) & 0xff) as u8])?;
}
Expand All @@ -25,7 +27,7 @@ pub fn write_varint(v: impl Into<u64>, w: &mut impl io::Write) -> Res<()> {
() if v < (1 << 14) => write_uint(2, v | (1 << 14), w),
() if v < (1 << 30) => write_uint(4, v | (2 << 30), w),
() if v < (1 << 62) => write_uint(8, v | (3 << 62), w),
() => panic!("Varint value too large"),
() => Err(Error::VariantTooLarge),
}
}

Expand Down Expand Up @@ -74,7 +76,9 @@ where
1 => ((b1 & 0x3f) << 8) | read_uint(1, r)?.ok_or(Error::Truncated)?,
2 => ((b1 & 0x3f) << 24) | read_uint(3, r)?.ok_or(Error::Truncated)?,
3 => ((b1 & 0x3f) << 56) | read_uint(7, r)?.ok_or(Error::Truncated)?,
_ => unreachable!(),
_ => {
return Err(Error::Unreachable);
}
}))
} else {
Ok(None)
Expand Down
9 changes: 8 additions & 1 deletion ohttp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ byteorder = "1.4"
chacha20poly1305 = {version = "0.8", optional = true}
hex = "0.4"
hkdf = {version = "0.11", optional = true}
hpke = {version = "0.11.0", optional = true, default-features = false, features = ["std", "x25519"]}
hpke = {version = "0.12.0", optional = true, default-features = false, features = ["std", "x25519", "p384"]}
lazy_static = "1.4"
log = {version = "0.4", default-features = false}
rand = {version = "0.8", optional = true}
Expand All @@ -39,6 +39,13 @@ regex-automata = {version = "~0.3", optional = true}
regex-syntax = {version = "~0.7", optional = true}
sha2 = {version = "0.9", optional = true}
thiserror = "1"
futures-util = "0.3.30"
futures = "0.3.30"
bytes = "1.7.2"
async-stream = "0.3.5"
tokio = { version = "1.40.0", features = ["full"] }
tracing = "0.1"
backtrace = "0.3"

[dependencies.hpke-pq]
package = "hpke_pq"
Expand Down
32 changes: 29 additions & 3 deletions ohttp/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,12 @@ impl KeyConfig {
}

/// Construct a configuration for the server side.
/// # Panics
/// If the configurations don't include a supported configuration.
pub fn new(key_id: u8, kem: Kem, mut symmetric: Vec<SymmetricSuite>) -> Res<Self> {
Self::strip_unsupported(&mut symmetric, kem);
assert!(!symmetric.is_empty());
if symmetric.is_empty() {
return Err(Error::SymmetricKeyEmpty);
}
let (sk, pk) = generate_key_pair(kem)?;
Ok(Self {
key_id,
Expand All @@ -78,6 +79,29 @@ impl KeyConfig {
})
}

/// Construct a configuration from an existing private key
/// # Panics
/// If the configurations don't include a supported configuration.
pub fn import_p384(
key_id: u8,
kem: Kem,
sk: <hpke::kem::DhP384HkdfSha384 as hpke::Kem>::PrivateKey,
pk: <hpke::kem::DhP384HkdfSha384 as hpke::Kem>::PublicKey,
mut symmetric: Vec<SymmetricSuite>,
) -> Res<Self> {
Self::strip_unsupported(&mut symmetric, kem);
if symmetric.is_empty() {
return Err(Error::SymmetricKeyEmpty);
}
Ok(Self {
key_id,
kem,
symmetric,
sk: Some(crate::rh::hpke::PrivateKey::P384(sk)),
pk: crate::rh::hpke::PublicKey::P384(pk),
})
}

/// Derive a configuration for the server side from input keying material,
/// using the `DeriveKeyPair` functionality of the HPKE KEM defined here:
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-hpke-12.html#section-4>
Expand All @@ -93,7 +117,9 @@ impl KeyConfig {
#[cfg(feature = "rust-hpke")]
{
Self::strip_unsupported(&mut symmetric, kem);
assert!(!symmetric.is_empty());
if symmetric.is_empty() {
return Err(Error::SymmetricKeyEmpty);
}
let (sk, pk) = derive_key_pair(kem, ikm)?;
Ok(Self {
key_id,
Expand Down
14 changes: 12 additions & 2 deletions ohttp/src/err.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pub enum Error {
#[cfg(feature = "rust-hpke")]
#[error("a problem occurred with the AEAD")]
Aead(#[from] aead::Error),
#[error("AEAD mode mismatch")]
AeadMode,
#[cfg(feature = "nss")]
#[error("a problem occurred during cryptographic processing: {0}")]
Crypto(#[from] crate::nss::Error),
Expand All @@ -22,16 +24,24 @@ pub enum Error {
InvalidKeyType,
#[error("the wrong KEM was specified")]
InvalidKem,
#[error("Invalid private key")]
InvalidPrivateKey,
#[error("io error: {0}")]
Io(#[from] std::io::Error),
#[error("the key ID was invalid")]
KeyId,
#[error("Returned a different key ID from the one requested : {0} {1}")]
KeyIdMismatch(u8, u8),
#[error("Symmetric key is empty")]
SymmetricKeyEmpty,
#[error("the configuration contained too many symmetric suites")]
TooManySymmetricSuites,
#[error("a field was truncated")]
Truncated,
#[error("the two lengths are not equal : {0} {1}")]
UnequalLength(usize, usize),
#[error("the configuration was not supported")]
Unsupported,
#[error("the configuration contained too many symmetric suites")]
TooManySymmetricSuites,
}

impl From<std::num::TryFromIntError> for Error {
Expand Down
6 changes: 6 additions & 0 deletions ohttp/src/hpke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ macro_rules! convert_enum {

convert_enum! {
pub enum Kem {
P384Sha384 = 17,

X25519Sha256 = 32,

#[cfg(feature = "pq")]
Expand All @@ -42,6 +44,8 @@ impl Kem {
#[must_use]
pub fn n_enc(self) -> usize {
match self {
Kem::P384Sha384 => 97,

Kem::X25519Sha256 => 32,

#[cfg(feature = "pq")]
Expand All @@ -52,6 +56,8 @@ impl Kem {
#[must_use]
pub fn n_pk(self) -> usize {
match self {
Kem::P384Sha384 => 97,

Kem::X25519Sha256 => 32,

#[cfg(feature = "pq")]
Expand Down
Loading

0 comments on commit 1e00204

Please sign in to comment.