Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: initial support for X25519Kyber768Draft00 PQC #210

Merged
merged 5 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ jobs:
platform: linux/arm64
tags-suffix: "-slim"

- target: "musl"
platform: linux/amd64
tags-suffix: "-slim-pq"

- target: "musl"
platform: linux/arm64
tags-suffix: "-slim-pq"

- target: "gnu"
build-feature: "-s2n"
platform: linux/amd64
Expand All @@ -44,6 +52,26 @@ jobs:
platform: linux/arm64
tags-suffix: "-s2n"

- target: "gnu"
build-feature: "-pq"
platform: linux/amd64
tags-suffix: "-pq"

- target: "gnu"
build-feature: "-pq"
platform: linux/arm64
tags-suffix: "-pq"

- target: "gnu"
build-feature: "-s2n-pq"
platform: linux/amd64
tags-suffix: "-s2n-pq"

- target: "gnu"
build-feature: "-s2n"
platform: linux/arm64
tags-suffix: "-s2n-pq"

- target: "gnu"
build-feature: "-webpki-roots"
platform: linux/amd64
Expand Down
37 changes: 37 additions & 0 deletions .github/workflows/release_docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ jobs:
jqtype/rpxy:latest
ghcr.io/junkurihara/rust-rpxy:latest

- target: "default-pq"
dockerfile: ./docker/Dockerfile
platforms: linux/amd64,linux/arm64
build-args: |
"CARGO_FEATURES=--no-default-features --features=http3-quinn,cache,rustls-backend,acme,post-quantum"
tags-suffix: "-pq"
# Aliases must be used only for release builds
aliases: |
jqtype/rpxy:pq
ghcr.io/junkurihara/rust-rpxy:pq

- target: "default-slim"
dockerfile: ./docker/Dockerfile-slim
build-contexts: |
Expand All @@ -42,6 +53,20 @@ jobs:
jqtype/rpxy:slim
ghcr.io/junkurihara/rust-rpxy:slim

- target: "default-slim-pq"
dockerfile: ./docker/Dockerfile-slim
build-args: |
"CARGO_FEATURES=--no-default-features --features=http3-quinn,cache,rustls-backend,acme,post-quantum"
build-contexts: |
messense/rust-musl-cross:amd64-musl=docker-image://messense/rust-musl-cross:x86_64-musl
messense/rust-musl-cross:arm64-musl=docker-image://messense/rust-musl-cross:aarch64-musl
platforms: linux/amd64,linux/arm64
tags-suffix: "-slim-pq"
# Aliases must be used only for release builds
aliases: |
jqtype/rpxy:slim-pq
ghcr.io/junkurihara/rust-rpxy:slim-pq

- target: "s2n"
dockerfile: ./docker/Dockerfile
build-args: |
Expand All @@ -54,6 +79,18 @@ jobs:
jqtype/rpxy:s2n
ghcr.io/junkurihara/rust-rpxy:s2n

- target: "s2n-pq"
dockerfile: ./docker/Dockerfile
build-args: |
"CARGO_FEATURES=--no-default-features --features=http3-s2n,cache,rustls-backend,acme,post-quantum"
"ADDITIONAL_DEPS=pkg-config libssl-dev cmake libclang1 gcc g++"
platforms: linux/amd64,linux/arm64
tags-suffix: "-s2n-pq"
# Aliases must be used only for release builds
aliases: |
jqtype/rpxy:s2n-pq
ghcr.io/junkurihara/rust-rpxy:s2n-pq

- target: "webpki-roots"
dockerfile: ./docker/Dockerfile
platforms: linux/amd64,linux/arm64
Expand Down
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
# CHANGELOG

## 0.9.3 or 0.10.0 (Unreleased)
## 0.10.0 (Unreleased)

## 0.9.3

### Improvement

- Feat: Support post-quantum `X25519Kyber768Draft00` for incoming TLS initiation. This is non-default feature [feature: `post-quantum`]. Upstream connection to backend applications does not yet support PQC.
- Feat: emit WARN messages if there exist unused and unsupported options specified in configuration file.
- Docs: `rpxy.io` is now available for the official website of `rpxy`.
- Refactor: lots of minor improvements
- Deps


## 0.9.2

### Improvement
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@

[^pure_rust]: Doubtfully can be claimed to be written in pure Rust since current `rpxy` is based on `aws-lc-rs` for cryptographic operations.

By default, `rpxy` provides the *TLS connection sanitization* by correctly binding a certificate used to establish a secure channel with the backend application. Specifically, it always keeps the consistency between the given SNI (server name indication) in `ClientHello` of the underlying TLS and the domain name given by the overlaid HTTP HOST header (or URL in Request line) [^1]. Additionally, as a somewhat unstable feature, our `rpxy` can handle the brand-new HTTP/3 connection thanks to [`quinn`](https://github.com/quinn-rs/quinn), [`s2n-quic`](https://github.com/aws/s2n-quic) and [`hyperium/h3`](https://github.com/hyperium/h3).[^h3lib] Furthermore, `rpxy` supports the automatic issuance and renewal of certificates via [TLS-ALPN-01 (RFC8737)](https://www.rfc-editor.org/rfc/rfc8737) of [ACME protocol (RFC8555)](https://www.rfc-editor.org/rfc/rfc8555) thanks to [`rustls-acme`](https://github.com/FlorianUekermann/rustls-acme).
By default, `rpxy` provides the *TLS connection sanitization* by correctly binding a certificate used to establish a secure channel with the backend application. Specifically, it always keeps the consistency between the given SNI (server name indication) in `ClientHello` of the underlying TLS and the domain name given by the overlaid HTTP HOST header (or URL in Request line) [^1]. Additionally, as a somewhat unstable feature, our `rpxy` can handle the brand-new HTTP/3 connection thanks to [`quinn`](https://github.com/quinn-rs/quinn), [`s2n-quic`](https://github.com/aws/s2n-quic) and [`hyperium/h3`](https://github.com/hyperium/h3).[^h3lib] Furthermore, `rpxy` supports the automatic issuance and renewal of certificates via [TLS-ALPN-01 (RFC8737)](https://www.rfc-editor.org/rfc/rfc8737) of [ACME protocol (RFC8555)](https://www.rfc-editor.org/rfc/rfc8555) thanks to [`rustls-acme`](https://github.com/FlorianUekermann/rustls-acme), and the hybridized post-quantum key exchange [`X25519Kyber768Draft00`](https://datatracker.ietf.org/doc/draft-tls-westerbaan-xyber768d00/)[^kyber] for TLS initiation thanks to `rustls-post-quantum` crate.

[^h3lib]: HTTP/3 libraries are mutually exclusive. You need to explicitly specify `s2n-quic` with `--no-default-features` flag. Also note that if you build `rpxy` with `s2n-quic`, then it requires `openssl` just for building the package.

[^kyber]: This is not yet a default feature. You need to specify `--features post-quantum` when building `rpxy`. Also note that `X25519Kyber768Draft00` is a draft version yet this is widely used on the Internet. We will update the feature when the newest version (`X25519MLKEM768` in [`ECDHE-MLKEM`](https://www.ietf.org/archive/id/draft-kwiatkowski-tls-ecdhe-mlkem-02.html)) is available.

This project is still *work-in-progress*. But it is already working in some production environments and serves a number of domain names. Furthermore it *significantly outperforms* NGINX and Caddy, e.g., *1.5x faster than NGINX*, in the setting of a very simple HTTP reverse-proxy scenario (See [`bench`](./bench/) directory).

[^1]: We should note that NGINX doesn't guarantee such a consistency by default. To this end, you have to add `if` statement in the configuration file in NGINX.
Expand Down
2 changes: 2 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ Differences among tags are summarized as follows.
- `latest`: Built from the `main` branch with default features, running on Ubuntu.
- `latest-slim`, `slim`: Built by `musl` from the `main` branch with default features, running on Alpine.
- `latest-s2n`, `s2n`: Built from the `main` branch with the `http3-s2n` feature, running on Ubuntu.
- `*-pq`: Built with the `post-quantum` feature. This feature supports the post-quantum key exchange using `rustls-post-quantum` crate.

### Nightly Builds

- `nightly`: Built from the `develop` branch with default features, running on Ubuntu.
- `nightly-slim`: Built by `musl` from the `develop` branch with default features, running on Alpine.
- `nightly-s2n`: Built from the `develop` branch with the `http3-s2n` feature, running on Ubuntu.
- `*-pq`: Built with the `post-quantum` feature. This feature supports the hybridized post-quantum key exchange using `rustls-post-quantum` crate.

## Caveats

Expand Down
8 changes: 6 additions & 2 deletions rpxy-acme/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,29 @@ readme.workspace = true
edition.workspace = true
publish.workspace = true

[features]
post-quantum = ["rustls-post-quantum"]

[dependencies]
url = { version = "2.5.2" }
rustc-hash = "2.0.0"
thiserror = "1.0.65"
thiserror = "1.0.66"
tracing = "0.1.40"
async-trait = "0.1.83"
base64 = "0.22.1"
aws-lc-rs = { version = "1.10.0", default-features = false, features = [
"aws-lc-sys",
] }
blocking = "1.6.1"
rustls = { version = "0.23.15", default-features = false, features = [
rustls = { version = "0.23.16", default-features = false, features = [
"std",
"aws_lc_rs",
] }
rustls-platform-verifier = { version = "0.3.4" }
rustls-acme = { path = "../submodules/rustls-acme/", default-features = false, features = [
"aws-lc-rs",
] }
rustls-post-quantum = { version = "0.1.0", optional = true }
tokio = { version = "1.41.0", default-features = false }
tokio-util = { version = "0.7.12", default-features = false }
tokio-stream = { version = "0.1.16", default-features = false }
3 changes: 3 additions & 0 deletions rpxy-acme/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ impl AcmeManager {
domains: &[String],
runtime_handle: Handle,
) -> Result<Self, RpxyAcmeError> {
#[cfg(not(feature = "post-quantum"))]
// Install aws_lc_rs as default crypto provider for rustls
let _ = rustls::crypto::CryptoProvider::install_default(rustls::crypto::aws_lc_rs::default_provider());
#[cfg(feature = "post-quantum")]
let _ = rustls::crypto::CryptoProvider::install_default(rustls_post_quantum::provider());

let acme_registry_dir = acme_registry_dir
.map(|v| v.to_ascii_lowercase())
Expand Down
5 changes: 4 additions & 1 deletion rpxy-bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ publish.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
# default = ["http3-quinn", "cache", "rustls-backend", "acme", "post-quantum"]
# default = ["http3-s2n", "cache", "rustls-backend", "acme", "post-quantum"]
default = ["http3-quinn", "cache", "rustls-backend", "acme"]
# default = ["http3-s2n", "cache", "rustls-backend", "acme"]
http3-quinn = ["rpxy-lib/http3-quinn"]
Expand All @@ -22,6 +24,7 @@ rustls-backend = ["rpxy-lib/rustls-backend"]
webpki-roots = ["rpxy-lib/webpki-roots"]
cache = ["rpxy-lib/cache"]
acme = ["rpxy-lib/acme", "rpxy-acme"]
post-quantum = ["rpxy-lib/post-quantum"]

[dependencies]
rpxy-lib = { path = "../rpxy-lib/", default-features = false, features = [
Expand All @@ -31,7 +34,7 @@ rpxy-lib = { path = "../rpxy-lib/", default-features = false, features = [
mimalloc = { version = "*", default-features = false }
anyhow = "1.0.91"
rustc-hash = "2.0.0"
serde = { version = "1.0.213", default-features = false, features = ["derive"] }
serde = { version = "1.0.214", default-features = false, features = ["derive"] }
tokio = { version = "1.41.0", default-features = false, features = [
"net",
"rt-multi-thread",
Expand Down
6 changes: 4 additions & 2 deletions rpxy-certs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ publish.workspace = true

[features]
default = ["http3"]
post-quantum = ["rustls-post-quantum"]
http3 = []

[dependencies]
rustc-hash = { version = "2.0.0" }
tracing = { version = "0.1.40" }
derive_builder = { version = "0.20.2" }
thiserror = { version = "1.0.65" }
thiserror = { version = "1.0.66" }
hot_reload = { version = "0.1.6" }
async-trait = { version = "0.1.83" }
rustls = { version = "0.23.15", default-features = false, features = [
rustls = { version = "0.23.16", default-features = false, features = [
"std",
"aws_lc_rs",
] }
Expand All @@ -30,6 +31,7 @@ rustls-webpki = { version = "0.102.8", default-features = false, features = [
"std",
"aws_lc_rs",
] }
rustls-post-quantum = { version = "0.1.0", optional = true }
x509-parser = { version = "0.16.0" }

[dev-dependencies]
Expand Down
7 changes: 5 additions & 2 deletions rpxy-certs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ mod log {
use crate::{error::*, log::*, reloader_service::DynCryptoSource};
use hot_reload::{ReloaderReceiver, ReloaderService};
use rustc_hash::FxHashMap as HashMap;
use rustls::crypto::{aws_lc_rs, CryptoProvider};
use rustls::crypto::CryptoProvider;
use std::sync::Arc;

/* ------------------------------------------------ */
Expand Down Expand Up @@ -44,8 +44,11 @@ where
T: CryptoSource<Error = RpxyCertError> + Send + Sync + Clone + 'static,
{
info!("Building certificate reloader service");
#[cfg(not(feature = "post-quantum"))]
// Install aws_lc_rs as default crypto provider for rustls
let _ = CryptoProvider::install_default(aws_lc_rs::default_provider());
let _ = CryptoProvider::install_default(rustls::crypto::aws_lc_rs::default_provider());
#[cfg(feature = "post-quantum")]
let _ = CryptoProvider::install_default(rustls_post_quantum::provider());

let source = crypto_source_map
.iter()
Expand Down
3 changes: 3 additions & 0 deletions rpxy-certs/src/server_crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,10 @@ mod tests {

#[tokio::test]
async fn test_server_crypto_base_try_into() {
#[cfg(not(feature = "post-quantum"))]
let _ = CryptoProvider::install_default(rustls::crypto::aws_lc_rs::default_provider());
#[cfg(feature = "post-quantum")]
let _ = CryptoProvider::install_default(rustls_post_quantum::provider());

let mut server_crypto_base = ServerCryptoBase::default();

Expand Down
12 changes: 9 additions & 3 deletions rpxy-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ native-tls-backend = ["hyper-tls"]
rustls-backend = ["hyper-rustls"]
webpki-roots = ["rustls-backend", "hyper-rustls/webpki-tokio"]
acme = ["dep:rpxy-acme"]
post-quantum = [
"rustls-post-quantum",
"rpxy-acme/post-quantum",
"rpxy-certs/post-quantum",
]

[dependencies]
rand = "0.8.5"
Expand All @@ -49,13 +54,13 @@ async-trait = "0.1.83"

# Error handling
anyhow = "1.0.91"
thiserror = "1.0.65"
thiserror = "1.0.66"

# http for both server and client
http = "1.1.0"
http-body-util = "0.1.2"
hyper = { version = "1.5.0", default-features = false }
hyper-util = { version = "0.1.9", features = ["full"] }
hyper-util = { version = "0.1.10", features = ["full"] }
futures-util = { version = "0.3.31", default-features = false }
futures-channel = { version = "0.3.31", default-features = false }

Expand All @@ -74,7 +79,8 @@ hyper-rustls = { version = "0.27.3", default-features = false, features = [
# tls and cert management for server
rpxy-certs = { path = "../rpxy-certs/", default-features = false }
hot_reload = "0.1.6"
rustls = { version = "0.23.15", default-features = false }
rustls = { version = "0.23.16", default-features = false }
rustls-post-quantum = { version = "0.1.0", optional = true }
tokio-rustls = { version = "0.26.0", features = ["early-data"] }

# acme
Expand Down
7 changes: 5 additions & 2 deletions rpxy-lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{
use futures::future::join_all;
use hot_reload::ReloaderReceiver;
use rpxy_certs::ServerCryptoBase;
use rustls::crypto::{aws_lc_rs, CryptoProvider};
use rustls::crypto::CryptoProvider;
use std::sync::Arc;
use tokio_util::sync::CancellationToken;

Expand Down Expand Up @@ -101,8 +101,11 @@ pub async fn entrypoint(
info!("Cache is disabled")
}

#[cfg(not(feature = "post-quantum"))]
// Install aws_lc_rs as default crypto provider for rustls
let _ = CryptoProvider::install_default(aws_lc_rs::default_provider());
let _ = CryptoProvider::install_default(rustls::crypto::aws_lc_rs::default_provider());
#[cfg(feature = "post-quantum")]
let _ = CryptoProvider::install_default(rustls_post_quantum::provider());

// 1. build backends, and make it contained in Arc
let app_manager = Arc::new(backend::BackendAppManager::try_from(app_config_list)?);
Expand Down
Loading